I've got a trait class which I need to specialize (and partial-specialize) many times.
Some partial specializations overlap:
template< typename T > struct C { };
template< typename T1, typename T2 > struct TRAIT { };
templa开发者_运维知识库te< typename T > struct TRAIT< T, T > { };
template< typename T1, typename T2 > struct TRAIT< C<T1>, C<T2> > { };
int main( ) {
// ERROR! could be both TRAIT<T,T> [with T = C<int>]
// and TRAIT<T1,T2> [with T1 = T2 = int]
TRAIT< C<int>, C<int> > foo;
return 0;
};
How am I supposed to get the same result with a working code?
I went crazy with enable_if
and is_same
, I'm not even sure anymore it's the right way...
Your best bet for this, if you can't avoid overlapping specialization, is to clarify all your overlaps. You'll need to write another specialization for
template< typename T> struct TRAIT< C<T>, C<T> > { };
...but, as everybody else said in the comments, it's best to avoid overlapping if at all possible. As others called out, the problem may not be overlapping specializations, it may be that this isn't the best approach to solve your problem.
The trick is to create a helper type that tells you if something is a C<Foo>
or not:
template <typename T> struct C {};
template <typename T> struct is_C {
static bool const value = false;
};
template <typename T> struct is_C<C<T>> {
static bool const value = true;
};
You were on the right track with enable_if
but is_same
seems to be a dead end:
#include <type_traits>
template <typename T1, typename T2, typename Enabled = void> struct Trait {
static char const test = 'D'; // default
};
template <typename T> struct Trait<
T,
T,
typename std::enable_if<!is_C<T>::value >::type
> {
static char const test = 'N'; // non-C
};
template <typename T1, typename T2> struct Trait<
T1,
T2,
typename std::enable_if< is_C<T1>::value && is_C<T2>::value >::type
> {
static char const test = 'C'; // some C
};
Which you can test easily now:
#include <iostream>
int main() {
Trait< C<int>, C<float> > foo1a;
Trait< C<int>, C<int> > foo1b;
Trait< int, int > foo2;
Trait< int, float > foo3;
std::cout << "Trait<C<int>,C<float>> : " << foo1a.test << std::endl; // prints 'C'
std::cout << "Trait<C<int>,C<int>> : " << foo1b.test << std::endl; // prints 'C'
std::cout << "Trait<int,int> : " << foo2.test << std::endl; // prints 'N'
std::cout << "Trait<int,float> : " << foo3.test << std::endl; // prints 'D'
return 0;
}
You can easily change that if you want your specialisation to work only with one of the parameters to be a C
or whatever you like.
Try:
template< typename T > struct C { };
template< typename T1, typename T2 = T1> struct TRAIT { };
// ^^^^^^^^^
// Default Type is T1
int main( )
{
TRAIT<C<int> > foo1;
TRAIT<C<int>, C<int> > foo2;
foo1 = foo2;
return 0;
};
精彩评论