问题
I want to write a template class
which checks a trait with SFINAE.
As classes can not be "overloaded" as I read in that post: template overloading and SFINAE working only with functions but not classes
I wrote the following code:
class AA { public: using TRAIT = int; };
class BB { public: using TRAIT = float; };
template < typename T, typename UNUSED = void> class X;
template < typename T>
class X<T, typename std::enable_if< std::is_same< int, typename T::TRAIT>::value, int >::type>
{
public:
X() { std::cout << "First" << std::endl; }
};
template < typename T>
class X<T, typename std::enable_if< !std::is_same< int, typename T::TRAIT>::value, unsigned int >::type>
{
public:
X() { std::cout << "Second" << std::endl; }
};
int main()
{
X<AA> a;
X<BB> b;
}
But it simply fails with:
error: aggregate 'X<AA> a' has incomplete type and cannot be defined
X<AA> a;
^
error: aggregate 'X<BB> b' has incomplete type and cannot be defined
X<BB> b;
It seams that none of the templates works but I get no hint from the compiler why both specializations fail.
回答1:
The specializations have to match the primary. The lookup rule for determining what X<AA>
is is to first match the primary and add the default types, which gets us to X<AA, void>
, and then try to match that against all the specializations. But none of your specializations match X<AA, void>
so you end up with the primary. The primary isn't a complete type, hence the error.
Why do none of them match? Because you wrote:
typename std::enable_if< std::is_same< int, typename T::TRAIT>::value, int >::type
For AA
that evalutes as int
, which doesn't match void
, so the specialization isn't considered. You just want:
typename std::enable_if< std::is_same< int, typename T::TRAIT>::value>::type
or really:
std::enable_if_t< std::is_same< int, typename T::TRAIT>::value>
Similarly, for BB
, the second specialization's second type evaluates as unsigned int
instead of void
- so it too doesn't match.
来源:https://stackoverflow.com/questions/37280531/specializing-class-with-sfinae