2012-03-27 11 views
13

Si hago¿Cómo puedo detectar si un tipo es una base visible de otro tipo?

struct A{}; 
struct C:private A{}; 

typedef char (&yes)[1]; 
typedef char (&no)[2]; 

template <typename B, typename D> 
struct Host 
{ 
operator B*() const; 
operator D*(); 
}; 

template <typename B, typename D> 
struct is_base_of 
{ 
template <typename T> 
static yes check(D*, T); 
static no check(B*, int); 

static const bool value = sizeof(check(Host<B,D>(), int())) == sizeof(yes); 
}; 

int main(){ 
std::cout<<is_base_of<A,C>::value<<std::endl; 
} 

me sale un 1. Me gustaría conseguir un 0 cuando C es una A privada, y un 1 cuando C es un público A.

[el código se deriva de How does `is_base_of` work?]

+0

Un poco fuera de tema, pero ¿puede realmente ofrecer una recompensa de X si su reputación es menor que X? –

+0

Eliminé mi respuesta que dice básicamente "no puedo" con plantillas y una alternativa a las plantillas que podrían hacerlo. –

Respuesta

4

¿Tiene acceso a un compilador compatible con C++ 11?

Si es así, puede combinar el uso de Chad de static_cast con decltype para crear una implementación de rasgo de tipo muy simple (como se demuestra en this question). Según la sugerencia de Jonathan Wakely, las referencias han sido reemplazadas por punteros para evitar falsos positivos cuando D define un operator B&().

template<typename> struct AnyReturn { typedef void type; }; 

template<typename B, typename D, typename Sfinae = void> 
struct is_base_of: std::false_type {}; 

template<typename B, typename D> 
struct is_base_of<B, D, 
    typename AnyReturn< decltype(static_cast<B*>(std::declval<D*>())) >::type 
>: std::true_type {}; 

Cuando se utiliza gcc 4.7:

struct Base {}; 
struct PublicDerived : public Base {}; 
struct PrivateDerived : private Base {}; 

int main() 
{ 
    std::cout << is_base_of<Base, PublicDerived >::value << std::endl; // prints 1 
    std::cout << is_base_of<Base, PrivateDerived>::value << std::endl; // prints 0 
    return 0; 
} 
+1

Buena respuesta, pero 'is_base_of ' da el resultado incorrecto si 'B' tiene' operator A &() 'es decir, la conversión a' A'. Eso se puede resolver cambiándolo para convertir punteros, por ejemplo, 'static_cast (std :: declval ())' –

+0

@JonathanWakely Ese es un gran punto; actualizado. ¡Gracias! –

+0

Esto también funciona con gcc 4.6.3, pero gcc 4.5.1 no compila para 'PrivateDerived':' error: 'Base' es una base inaccesible de 'PrivateDerived'. No tuve suerte tratando de hacer que esto (o cualquier variante de esto) funcione en VS 2010. Parece que no puede manejar la combinación de 'decltype' y' static_cast' en las plantillas, lo que podría producir un resultado incorrecto o incluso colapsar el compilador No podré verificar VS 2011 ya que no es compatible con XP. –

0

¿Necesita algo que se puede evaluar en tiempo de ejecución, o será suficiente un simple error de tiempo de compilación?

struct A {}; 
struct B : private A {}; 

int main() 
{ 
    B b; 

    // gives error C2243: 'static_cast' : conversion from 'B *' to 'A &' exists, but is inaccessible 
    A& a = static_cast<A&>(b); 

    return 0; 
} 
+1

gracias, pero necesito el valor en tiempo de compilación, no un error, para establecer una plantilla. Imagine la plantilla :: value> struct x {}; –

0

Con el fin de aplicar la resolución de sobrecarga en tiempo de compilación truco para detectar especificadores de acceso, debería al menos necesidad de que el acceso especificadores se le considera en la resolución de sobrecarga de tiempo se hace. Este no es el caso con C++ 03, por lo que no se puede hacer. Creo que C++ 11 cambia esto por lo que con algunas conversiones artificiales y SFINAE podrá implementarlo.

Actualización: Voy a ir n3242 sección de sobrecarga Resolución, y no puedo encontrar nada que pudiera indicar que el acceso especificadores se consideran para resultion sobrecarga en C++ 11.

Cuestiones relacionadas