Ну, что же, настало время проверить, как поведут себя компиляторы при обработке этого кода.
Начнем с доступного всем
онлайнового компилятора . Вводим текст примера и запускаем его на компиляцию. Оопс! Компилятор говорит, что код содержит ошибку!
цитата: |
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 решил сделать "как лучше", то есть по принципу: раз программист задал частичную специализацию, то значит он хотел ее использовать, а значит мы пойдем навстречу его пожеланиям. Но, однако, это некорректный подход.
Конечно, чтобы не было такой неоднозначности, следовало изначально написать корректный код, разместив частичную специализацию шаблона до ее первого возможного использования при инстанциировании, а не полагаться на то, что ваш компилятор "проглатывает" этот код без каких-либо замечаний.
Этот пример можно задавать в качестве вопроса соискателям на работу, когда кандидат вам не нравится, и вы хотите от него избавиться.
Так что делайте вывод: если вы не читаете раздел этого форума, то можете попасть впросак на собеседовании при приеме на работу!