Frank Bergemann Frank Bergemann - 1 month ago 11
C++ Question

Class template specialization within template class

Re-factoring legacy code I want to merge separate template classes/structs that are related to each other (to avoid namespace pollution).

Nested
(below) is a helper class for
MyStruct
, which i want to move into
MyStruct
.

But I cannot make this work:

#include <type_traits>
#include <iostream>

struct YES {} ;
struct NO {};

template <typename TYPE>
struct MyStruct
{

template <typename TYPE_AGAIN = TYPE, typename SELECTOR = NO>
struct Nested
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
}
};


template <>
struct Nested<TYPE, typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
{
static void Print(void)
{
std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
}
};

};


the compiler complains:

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
template <>
^
make: *** [main.o] Error 1


Actually it also bothers me to have to include


<typename TYPE_AGAIN = TYPE>



But without, there are even more complains:

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
template <>
^
../MyStruct.h:32:9: error: template parameters not used in partial specialization:
struct Nested<typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
^
../MyStruct.h:32:9: error: ‘TYPE’
make: *** [main.o] Error 1

Answer

You can't specialize templates in non-namespace scope, like a struct in your case.

You would have to put the specializations outside of the struct definition:

template<typename TYPE> template<>
struct MyStruct<TYPE>::Nested<...> {};

But now you have another problem, if you want to specialize a template inside of a template class, you'll have to specialize it for every template class. You can't just specialize one member function, you have to specialize the whole class.

So, you need to do this:

template<> template<>
struct MyStruct<int>::Nested<...> {};

Also, you really don't need SFINAE for this:

template<typename SELECTOR>
struct Nested; // Default invalid SELECTOR

template<>
struct Nested<YES> { /*...*/ };

template<>
struct Nested<NO> { /*...*/ };
Comments