Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
370 views
in Technique[技术] by (71.8m points)

c++ - Template specialization to use default type if class member typedef does not exist

I'm trying to write code that uses a member typedef of a template argument, but want to supply a default type if the template argument does not have that typedef. A simplified example I've tried is this:

struct DefaultType    { DefaultType()    { printf("Default ");    } };
struct NonDefaultType { NonDefaultType() { printf("NonDefault "); } };

struct A {};
struct B { typedef NonDefaultType Type; };

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
};
template<typename T> struct Get_Type< T, typename T::Type > {
    typedef typename T::Type  Type; 
};

int main()
{
    Get_Type<A>::Type test1;
    Get_Type<B>::Type test2;
}

I would expect this to print "Default NonDefault", but instead it prints "Default Default". My expectation is that the second line in main() should match the specialized version of Get_Type, because B::Type exists. However, this does not happen.

Can anyone explain what's going on here and how to fix it, or another way to accomplish the same goal?

Thank you.

Edit:

Georg gave an alternate method, but I'm still curious about why this doesn't work. According the the boost enable_if docs, a way to specialize a template for different types is like so:

template <class T, class Enable = void> 
class A { ... };

template <class T>
class A<T, typename enable_if<is_integral<T> >::type> { ... };

template <class T>
class A<T, typename enable_if<is_float<T> >::type> { ... };

This works because enable_if< true > has type as a typedef, but enable_if< false > does not.

I don't understand how this is different than my version, where instead of using enable_if I'm just using T::Type directly. If T::Type exists wouldn't that be the same as enable_if< true >::type in the above example and cause the specialization to be chosen? And if T::Type doesn't exist, wouldn't that be the same as enable_if< false >::type not existing and causing the default version to be chosen in the above example?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can do that by utilizing SFINAE:

template<class T> struct has_type {
    template<class U> static char (&test(typename U::Type const*))[1];
    template<class U> static char (&test(...))[2];
    static const bool value = (sizeof(test<T>(0)) == 1);
};

template<class T, bool has = has_type<T>::value> struct Get_Type {
    typedef DefaultType Type;
};

template<class T> struct Get_Type<T, true> { 
    typedef typename T::Type Type;
};

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...