В новом стандарте
C++ 2011 произошли изменения в описании относительно явной специализации шаблонных функций по сравнению с предыдущим стандартом
C++ 2003.
Ранее в стандарте
C++ 2003 в параграфе №2 раздела
14.7.3 Explicit specialization было написано следующее:
цитата: |
2 An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member. An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member. Such a declaration may also be a definition. If the declaration is not a definition, the specialization may be defined later in the namespace in which the explicit specialization was declared, or in a namespace that encloses the one in which the explicit specialization was declared. |
|
Другими словами, если первое объявление явной специализации шаблонной функции является одновременно и ее определением, то это определение должно быть задано в том же пространстве имен, в котором объявлен исходной шаблон.
В стандарте
C++ 2011 этот параграф был изменен:
цитата: |
2 An explicit specialization shall be declared in a namespace enclosing the specialized template. An explicit specialization whose declarator-id is not qualified shall be declared in the nearest enclosing namespace of the template, or, if the namespace is inline (7.3.1), any namespace from its enclosing namespace set. Such a declaration may also be a definition. If the declaration is not a definition, the specialization may be defined later (7.3.1.2). |
|
То есть теперь необязательно объявлять явную специализацию шаблонной функции в том же самом пространстве имен, где был объявлен исходный шаблон. Это можно сделать в охватывающем пространстве имен, квалифицировав имя шаблона. Следовательно и определение явной специализации шаблонной функции, которое одновременно является и ее первым объявлением можно делать в охватывающем пространстве имен.
Стандарт
C++2011 смягчил требования к объявлению явной специализации шаблонной функции. На это стоит обратить внимание.
Однако в связи с этим был обнаружен баг компилятора
GCC, который несложно воспроизвести на сайте онлайновых компиляторов www.ideone.com, если запустить на компиляцию следующую простую программу:
#include <iostream>
#include <utility>
#include <string>
namespace N
{
template <typename T1, typename T2>
void f( const T1 &, const T2 & )
{
}
}
template <>
void N::f( const std::pair<int, std::string>& lhs,
const std::pair<int, std::string>& rhs )
{
}
int main()
{
return 0;
}
Компилятор
GCC выдаст следующее сообщение об ошибке:
цитата: |
prog.cpp:18:48: error: specialization of ‘template<class T1, class T2> void N::f(const T1&, const T2&)’ in different namespace [-fpermissive] const std::pair<int, std::string>& rhs ) ^ prog.cpp:10:6: error: from definition of ‘template<class T1, class T2> void N::f(const T1&, const T2&)’ [-fpermissive] void f( const T1 &, const T2 & ) ^ |
|
Интересно отметить, что этот код успешно компилируется более старым компилятором
MS VC++ 2010.
Хочу предупредить, что, естественно, эта информация о баге компилятора актуальна на день написания этого сообщения.
Так что когда вы будете его читать, вполне возможно, что этот баг компилятора уже исправлен.