Форум » C/C++ » Частичная специализация шаблона - непредсказуемость результата » Ответить

Частичная специализация шаблона - непредсказуемость результата

Сыроежка: Основная проблема для программистов, имеющих дело с С++, состоит в том, что очень часто нельзя заранее сказать, какой результат вы получите при компиляции и выполнении заданного кода при использовании того или иного компилятора С++. Это кажется абсурдным, так как возникает естественный вопрос: а как вообще в таком случае программировать на С++, если вы даже не можете сказать, что у вас в итоге выйдет?! Спасти в этой ситуации программиста может лишь одно: знание стандарта С++. По крайней мере, зная стандарт С++, вы сможете ответить на вопрос, как должно быть, и является ли некорректная работа вашей программы результатом вашей собственной ошибки, или же это - ошибка используемого вами компилятора С++, который обрабатывает код не в соответствии со стандартом.С++. Ситуация осложняется еще тем, что в стандарте С++ очень часто можно встретить оговорку, что компилятор не обязан выдавать диагностическое сообщение, если ему встретился тот или иной некорректный код. В качестве иллюстрации высказанного мною утверждения, можно рассмотреть простой пример использования частичной специализации шаблона, и каков получится результат, при компиляции и выполнении этого примера с использованием различных компиляторов С++. Вот сам пример. [pre2]#include <iostream> namespace N1 { template <typename T1, typename T2> struct A { A() { std::cout << "Primary template\n"; } }; } using N1::A; A<char, int> a1; namespace N1 { template <typename T> struct A<T, int> { A() { std::cout << "Partial specialization\n"; } }; } A<char, int> a2; int main() { return 0; }[/pre2] В этом примере в пространстве имен N1 сначала объявляется первичный шиблон структуры A, а затем ниже его частичная специализация, когда второй аргумент шаблона имеет тип int. Возникает два вопроса. Первый - будет ли вообще компилироваться этот код? Второй - если код будет скомпилирован, то какой результат будет получен при выполнении примера, то есть что будет выведено на консоль при вызове конструкторов этого шаблонного класса A при создании объектов a1 и a2? Не спешите сразу же бежать к вашему любимому компилятору С++ и проверять, что выйдет в результате компиляции и выполнения примера, если до его выполнения вообще дойдет дело. Сначала изучите код визуально и поразмыслите над ним. Как на ваш взгляд, а не на взгляд вашего любимого компилятора является ли код корректным, и что получится в случае его выполнения. Для этого я сделаю небольшую паузу прежде, чем продемонстрирую, как ведут себя по отношению к этому коду некоторые используемые мною компиляторы, и что по этому поводу говорит стандарт С++.

Ответов - 1

Сыроежка: Ну, что же, настало время проверить, как поведут себя компиляторы при обработке этого кода. Начнем с доступного всем онлайнового компилятора . Вводим текст примера и запускаем его на компиляцию. Оопс! Компилятор говорит, что код содержит ошибку! error: partial specialization of 'N1::A<T, int>' after instantiation of 'N1::A<char, int>' Текст ошибки достаточно ясен: объявление частичной специализации шаблона A<T, int>, которая могла бы испоользоваться при определении объектов a1 и a2, встретилась уже после инстанциирования (реализации) первичного шаблона, которое произошло при определении объекта a1. Итак, программист, который использовал для тестирования этот компилятор, уверенно доложит, что код некорректный и не должен компилироваться. Но у другого программиста после тестирования этого кода на своем уже давно используемом им компиляторе, как, например, Borland C++ Builder 5.0, будет другое мнение. Его код успешно скомпилируется и выдаст результат Primary template Partial specialization Чтобы выяснить, кто из двух программистов, или, может быть точнее сказать, компиляторов прав нужен арбитр, то есть третий программист со своим компилятором и причем желательно более современным. Такой программист с компилятором MS VC++ 2010 быстро находится, и первые два программиста с нетерпением ждут от него сообщения о результате компиляции и выполнения данного примера. Естественно долго ждать не придется, так как пример очень простой. Компилятор MS VC++ 2010 также совершенно без всяких замечаний скомпилирует данный пример и выдаст...совершенно другой результат! Primary template Primary template Итак, три компилятора - три различных результата компиляции и выполнения одного и того же кода, начиная от полного неприятия кода, до вывода двух различных результатов на консоль. Тут голова кругом пойдет! Единственный путь разобраться с этим кодом - это обратиться к стандарту С++. В разделе "14.5.5 Class template partial specializations" в первом же параграфе написано: A partial specialization shall be declared before the first use of a class template specialization that would make use of the partial specialization as the result of an implicit or explicit instantiation in every translation unit in which such a use occurs; no diagnostic is required. Обратите внимание на последние слова в этой фразе: no diagnostic is required. Это означает, что компилятор может рассматривать данную ситуацию, когда частичная специализация шаблона объявляется уже после инстанциирования, как ошибочную и выдать соответствующее сообщение об ошибке, а может не выдавать никакого сообщения и продолжить работу в соответствии со своей логикой. Первый используемый онлайновый компилятор посчитал, что будет лучше, если обратить внимание программиста на не совсем корректный код и выдать сообщение об ошибке. Два других компилятора, Borland C++ Builder 5.0 и MS VC++ 2010, решили самостоятельно справиться с этим кодом без участия программиста. Теперь осталось разобраться, а какой из двух результатов работы программы верный? Так как класс уже был инстанциирован, то при определении второго объекта a2 компилятор должен был предпочесть уже инстанциированный класс для заданных шаблонных аргументов. Это и сделал компилятор MS VC++ 2010. Компилятор же Borland C++ Builder решил сделать "как лучше", то есть по принципу: раз программист задал частичную специализацию, то значит он хотел ее использовать, а значит мы пойдем навстречу его пожеланиям. Но, однако, это некорректный подход. Конечно, чтобы не было такой неоднозначности, следовало изначально написать корректный код, разместив частичную специализацию шаблона до ее первого возможного использования при инстанциировании, а не полагаться на то, что ваш компилятор "проглатывает" этот код без каких-либо замечаний. Этот пример можно задавать в качестве вопроса соискателям на работу, когда кандидат вам не нравится, и вы хотите от него избавиться. Так что делайте вывод: если вы не читаете раздел этого форума, то можете попасть впросак на собеседовании при приеме на работу!



полная версия страницы