I have created a template class to provide details about enums.
template <typename TEnum>
struct enum_traits
{
struct enumerators
{
constexpr static const size_t size = 0;
template <size_t TIndex>
struct get {
constexpr static TEnum value = static_cast<TEnum>( 0 );
constexpr static const char *identifier = "";
};
};
};
This is specialised for certain enums - in this case MyEnum:
enum class MyEnum : int
{
eValue1 = 2,
eValue2 = 4,
eValue3 = 7,
eValue4 = 8,
eValue5 = 11,
eValue6 = 13,
};
template<>
struct enum_traits<MyEnum>
{
struct enumerators
{
constexpr static const size_t size = 6;
constexpr static const std::array<MyEnum, size> values{ {
MyEnum::eValue1,
MyEnum::eValue2 ,
MyEnum::eValue3,
MyEnum::eValue4 ,
MyEnum::eValue5,
MyEnum::eValue6 ,
} };
constexpr static const std::array<const char*, size> names{ {
"eValue1",
"eValue2",
"eValue3",
"eValue4",
"eValue5",
"eValue6",
} };
template <size_t TIndex>
struct get {
constexpr static const MyEnum value{ values.at( TIndex ) };
constexpr static const char* identifier{ names.at( TIndex ) };
};
};
};
and I would use it in code like so
auto name2 = enum_traits<MyEnum>::enumerators::names[2];
However when compiling with clang I get this link error
L0039: reference to undefined symbol `enum_traits<MyEnum>::enumerators::names' in file "/generated_got_file/"
If I compile with the microsoft compiler for windows platform then it works fine. If I change the line to use a constexpr as below then that works too but that is not what I need.
constexpr auto name2 = enum_traits<MyEnum>::enumerators::names[2];
Can anyone suggest why I might be getting the error and what possible workarounds I could use?
UPDATE
Solution is to have in a cpp file somewhere the lines
constexpr const std::array<MyEnum, enum_traits<MyEnum>::enumerators::size> enum_traits<MyEnum>::enumerators::values;
constexpr const std::array<const char*, enum_traits<MyEnum>::enumerators::size> enum_traits<MyEnum>::enumerators::names;
Although vstudio doesn't seem to need the explicit definition clang obviously wants the storage defined for the non-integral data members
I think I was confused by the constexpr because the usual way I have static data members is to declare them in the header and define them in the source. With constexpr static data members it seems like it is the opposite way round.