2012-04-27 21 views
8

considerar lo siguiente:¿Plantilla especializada de C++ basada en la presencia/ausencia de un miembro de la clase?

struct A { 
    typedef int foo; 
}; 

struct B {}; 

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

que quieran especializarse C de modo que C <Un> obtiene una especialización y C <B> pone la otra, en base a la presencia o ausencia de nombre de tipo T :: foo. ¿Es posible usar rasgos de tipo o alguna otra magia de plantilla?

El problema es que todo lo que he intentado produce un error de compilación al crear instancias de C <B> porque B :: foo no existe. ¡Pero eso es lo que quiero probar!


Editar: creo que la respuesta de Ildjarn es mejor, pero finalmente se le ocurrió la siguiente solución C++ 11. El hombre es jacky, pero al menos es corto. :)

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

Usted debería haber dicho que estaban interesados ​​en una solución de C++ 11. : -] El tuyo está bien, pero la sobrecarga 'has_foo (T *)' podría mejorarse al devolver 'bool' y usar la expresión SFINAE, por lo que no es necesario el lanzamiento en el callsite. – ildjarn

+0

'(T *) 0)' debe ser 'declval ()', probablemente – Lol4t0

Respuesta

6

Otro (C++ 03) Enfoque:

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

Algo como esto podría ayudar: 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 {}; 
Cuestiones relacionadas