2012-04-27 15 views
8

Si consideri il seguente:Specializzazione del modello C++ basato sulla presenza/assenza di un membro della classe?

struct A { 
    typedef int foo; 
}; 

struct B {}; 

template<class T, bool has_foo = /* ??? */> 
struct C {}; 

voglio specializzarmi C in modo che C <Un> ottiene una specializzazione e C <B> ottiene l'altro, in base alla presenza o assenza di typename T :: foo. È possibile ciò usando tratti tipografici o qualche altro modello magico?

Il problema è che tutto ciò che ho provato produce un errore di compilazione durante l'istanziazione di C <B> perché B :: pippo non esiste. Ma è quello che voglio testare!


Edit: Penso risposta di Ildjarn è meglio, ma alla fine mi si avvicinò con la seguente soluzione C++ 11. L'uomo è hacky, ma almeno è breve. :)

template<class T> 
constexpr typename T::foo* has_foo(T*) { 
    return (typename T::foo*) 1; 
} 
constexpr bool has_foo(...) { 
    return false; 
} 
template<class T, bool has_foo = (bool) has_foo((T*)0)> 
+0

Si dovrebbe aver detto che eri interessato a una soluzione C++ 11. : -] Il tuo va bene, ma il sovraccarico di 'has_foo (T *)' potrebbe essere migliorato restituendo 'bool' e usando l'espressione SFINAE, quindi nessun cast è necessario nel callsite. – ildjarn

+0

'(T *) 0)' dovrebbe essere 'declval ()', probabilmente – Lol4t0

risposta

6

Altro (C++ 03) approccio:

template<typename T> 
struct has_foo 
{ 
private: 
    typedef char no; 
    struct yes { no m[2]; }; 

    static T* make(); 
    template<typename U> 
    static yes check(U*, typename U::foo* = 0); 
    static no check(...); 

public: 
    static bool const value = sizeof(check(make())) == sizeof(yes); 
}; 

struct A 
{ 
    typedef int foo; 
}; 

struct B { }; 

template<typename T, bool HasFooB = has_foo<T>::value> 
struct C 
{ 
    // T has foo 
}; 

template<typename T> 
struct C<T, false> 
{ 
    // T has no foo 
}; 
2

Qualcosa di simile potrebbe aiutare: has_member.

typedef char (&no_tag)[1]; 
typedef char (&yes_tag)[2]; 

template< typename T > no_tag has_member_foo_helper(...); 

template< typename T > yes_tag has_member_foo_helper(int, void (T::*)() = &T::foo); 

template< typename T > struct has_member_foo { 
    BOOST_STATIC_CONSTANT(bool 
     , value = sizeof(has_member_foo_helper<T>(0)) == sizeof(yes_tag) 
     ); }; 

template<class T, bool has_foo = has_member_foo<T>::value> 
struct C {}; 
Problemi correlati