2011-12-15 5 views
5

Tengo una función de plantilla y deseo asegurarme en tiempo de compilación de que no está instanciado en un subtipo o supertipo de una clase en particular.¿Cómo puedo crear una afirmación en tiempo de compilación de que una plantilla es de tipos específicos?

¿Cómo puedo causar un error del compilador de C++ si se infringe esto?

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

template <typename T> 
bool isCorrect(const T& obj) { 
    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

Quiero isCorrect a ser sólo está disponible para la clase derived, pero no base o lowest. Tenga en cuenta que podría haber muchas otras clases más bajas y una cadena de clases base para excluir, así como clases alternativas derivadas que son aceptables.

¿Existe alguna manera en C++ de limitar la plantilla para que solo se aplique a las clases derivadas que especifico explícitamente?

+0

posible duplicado de [Restricciones Plantilla C++] (http://stackoverflow.com/questions/122316/template-constraints-c) –

+0

Específicamente, esto podría ser útil: http://www.boost.org/doc/libs/1_48_0/libs/concept_check/concept_check.htm –

+0

¿Por qué no escribes sobrecargas? – GManNickG

Respuesta

4

Aquí hay una técnica que conozco.

Primero, haga otra clase de plantilla policy_enforcer. Declarar esta clase sin definirlo, y también proporcionar una especialización de la misma para derivedque también se define:

template<typename T> struct policy_enforcer; 
template<> struct policy_enforcer<derived> { }; 

Luego, dentro de la función que desea bloquear, incluyen la expresión sizeof(policy_enforcer<T>). Como sizeof en tipos incompletos es un error de compilación, esto evitará que el código se compile.

actualiza con código vivo:using base, using derived, using lowest.

+0

Un poco obtuso, pero funcionaría. Con suerte, alguien publicará una forma que no sea tan oscura. – WilliamKF

9

Escriba rasgos, específicamente is_base_of.

#include <type_traits> 

template <typename T> 
bool isCorrect(const T& obj) { 
    static bool const is_base = std::is_base_of<base, T>::value; 
    static bool const derives = std::is_base_of<derived, T>::value; 
    // specify allowed types here 
    static bool const is_derived = std::is_same<T, derived>::value; 
    // --- 
    static_assert((!is_base && !derives) || is_derived, "wrong argument type"); 

    typedef foo<T> D; 
    foo<T> *def = foo<T>::find(); 
    return (def && def->getAnswer(object)); 
} 

Tenga en cuenta que este es C++ 11 específica, pero se puede obtener el mismo comportamiento con Boost.TypeTraits.

1

Puede usar la especialización de plantilla.

Puede implementar solo isCorrect solo para los tipos con los que desee poder trabajar.

Para los otros tipos puede implementar el método ficticio, devolviendo false por ejemplo, o no implementando isCorrect en absoluto, en cuyo caso no se compilará para otros tipos.

#include <iostream> 

using namespace std; 

class base { 
}; 
class derived : public base { 
}; 
class lowest : public derived { 
}; 

// using this it will fail if you try to pass anything 
// else than `derived` 
// template <typename T> 
//  bool isCorrect(const T& obj); 

template <typename T> 
bool isCorrect(const T& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return false; 
} 

template <> 
bool isCorrect<derived>(const derived& obj) { 
    cout << __PRETTY_FUNCTION__ << endl; 
    return true; 
// typedef foo<derived> D; 
// foo<derived> *def = foo<derived>::find(); 
// return (def && def->getAnswer(object)); 
} 

prueba:

int main() 
{ 
    base b; 
    derived d; 
    lowest l; 

    cout << isCorrect(b) << endl; 
    cout << isCorrect(d) << endl; 
    cout << isCorrect(l) << endl; 
} 

de salida:

bool isCorrect(const T&) [with T = base] 
0 
bool isCorrect(const T&) [with T = derived] 
1 
bool isCorrect(const T&) [with T = lowest] 
0 
+0

'__func__' es el equivalente de C++ 11 de' __FUNCTION__', '__PRETTY_FUNCTION__' etc. – Xeo

+0

No es equivalente ... En primer lugar, no veo ningún requisito para C++ 11, nada está mal con' __PRETTY_FUNCTION__ ', no era parte de la pregunta, gracias por la información :)? Con '__func__' o' __FUNCTION__' solo obtienes 'isCorrect' or' isCorrect 'para que no veas los otros tipos que llamaron a la versión no especializada .... – stefanB

+0

No pasa nada, solo quería mencionar eso, ya que C++ 11 es el estándar actual. Todo lo demás ('__FUNCTION__',' __PRETTY_FUNCTION__', etc.) no es estándar ni portátil la mayor parte del tiempo. :) – Xeo

Cuestiones relacionadas