I'm developing a cross-platform library using C++. MSVC compiles fine but g++ is giving me problems. Suppose I have the following Enum helper class:
// 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
Here is the intended use:
// 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++ gives me a "Specialization of template in different namespace" error. Wrapping the DECLARE_ENUM block in namespace MyLib solves this problem. My question is why do I have to do this and is there another way of fixing this that doesn't require me to add a namespace MyLib around the block?
This changed in C++11 as a result of CWG issue 374 and N3064. The current wording (§14.7.3 [temp.expl.spec]/p2) is:
Since your declarator-id is in fact qualified with
MyLib::
, and the global namespace is a "namespace enclosing the specialized template", this looks like a GCC bug (bug 56480). Your code compiles fine with clang in C++11 mode.In C++98, however, the specialization must be put inside namespace in which the template is a member (see Mark B's comment below), and clang will produce a warning if put in C++98 mode.