模板在不同命名空间中的专门化

我正在开发一个使用C ++的跨平台库。 MSVC编译罚款,但克++是给我的问题。 假设我有以下的Enum助手类:

// File: Enum.h #ifndef ENUM_H #define ENUM_H #include <map> #include <cstring> namespace MyLib { #define DECLARE_ENUM( type ) template<> std::map<const char*, type> \ MyLib::Enum<type>::mMap = std::map<const char*, type>(); \ template<> MyLib::Enum<type>::Enum (void) template <typename Type> class Enum { private: Enum (void); public: static int Size (void) { /* ... */ return 0; } private: static std::map<const char*, Type> mMap; }; } #endif 

这是预期的用途:

 // SomeFile.cpp #include "Enum.h" enum MyEnum { value1, value2, value3, }; DECLARE_ENUM (MyEnum) { mMap["value1"] = value1; mMap["value2"] = value2; mMap["value3"] = value3; } void SomeFunc (void) { cout << Enum<MyEnum>::Size(); } 

g ++给了我一个“不同命名空间中的模板专业化”的错误。 包装命名空间MyLib中的DECLARE_ENUM块可解决此问题。 我的问题是为什么我必须这样做,是否有另一种解决方法,不需要我添加一个命名空间MyLib周围的块?

由于CWG问题374和N3064,这在C ++ 11中发生了变化 。 目前的措辞(§14.7.3[temp.expl.spec] / p2)是:

明确的专门化应该在封装专门模板的名称空间中声明。 其声明符不具有限定的显式特化应在模板的最近的封闭名称空间中声明,或者如果名称空间是内联(7.3.1),则从其封闭名称空间集合中声明任何名称空间。

既然你的declarator-id实际上是用MyLib::限定的,而且全局命名空间是一个“封装专用模板的命名空间”,这就像一个GCC bug( 错误56480 )。 你的代码在C ++ 11模式下可以很好地编译。

然而,在C ++ 98中,专业化必须放在模板所在的名称空间中(参见下面的Mark B的注释),而且如果使用C ++ 98模式 ,clang会产生一个警告。