C ++: cómo exigir que un tipo de plantilla se derive del otro

En un operador de comparación:

template bool operator==(Manager m1, Manager m2) { return m1.internal_field == m2.internal_field; } 

¿Hay alguna manera de que pueda hacer cumplir que R1 y R2 deben tener un supertipo o relación de subtipo? Es decir, me gustaría permitir que R1 se derive de R2 o que R2 se derive de R1, pero no permite la comparación si R1 y R2 son tipos no relacionados.

Un rasgo que desea podría verse así:

 template  struct is_base_of // check if B is a base of D { typedef char yes[1]; typedef char no[2]; static yes& test(B*); static no& test(...); static D* get(void); static const bool value = sizeof(test(get()) == sizeof(yes); }; 

Entonces solo necesitas una afirmación estática de algún tipo:

 // really basic template  struct static_assert; template <> struct static_assert {}; // only true is defined #define STATIC_ASSERT(x) static_assert<(x)>() 

Luego junta los dos:

 template bool operator==(Manager m1, Manager m2) { STATIC_ASSERT(is_base_of::value || is_base_of::value); return p1.internal_field == p2.internal_field; } 

Si uno no deriva del otro, la función no se comstackrá. (Su error será similar a ” static_assert no definido”, y apuntará a esa línea).

Puedes usar los tipos de boost ( is_base_of ) y boost’s enable_if .

 #include  #include  template  struct has_derived_base_relationship : boost::integral_constant< bool, boost::is_base_of::value || boost::is_base_of::value > {}; template typename boost::enable_if, bool>::type operator==(Manager m1, Manager m2) { return p1.internal_field == p2.internal_field; } 

Por otro lado, ¿por qué el operador == uso tiene más valor con los tipos del mismo árbol de herencia? ¿No tendría que usar doble despacho para lograr resultados significativos?

En este post estoy considerando el problema de verificar si un tipo coincide exactamente con otro, no es exactamente lo que se solicita, pero es más simple y espero que pueda ayudar a comprender los trucos de plantilla aplicados.

Como se hizo en el impulso, se pueden adoptar especializaciones de plantilla para esa tarea, de hecho, puede definir una estructura de plantilla que contenga operaciones en un tipo dado, y utilizar estructuras de plantilla anidadas para esas operaciones. En nuestro caso:

 // Working on a specific type: template  struct is_type { // For all types T2!=T1 produce false: template  struct same_of { static const bool value = false; }; // Specialization for type T2==T1 producing true: template <> struct same_of { static const bool value = true; }; }; 

La definición de una macro permite usarla fácilmente:

 #define is_type_same(T1,T2) (is_type::same_of::value) 

como sigue:

 template bool operator==(Manager m1, Manager m2) { return is_type_same(R1,R2) && m1.internal_field == m2.internal_field; } 

Si el concept s se hubiera incluido en C ++ 0x, podría haber sido capaz de usarlos con un comstackdor que los implementa (como gcc).

Como no es el caso, la única alternativa actualmente disponible para hacer lo que usted desea parece ser la biblioteca Boost Concept Check .

 template struct Derived_from { static void constraints(T* p) { B* pb = p; } Derived_from() { void(*p)(T*) = constraints; } }; template bool test(R1& r1) { Derived_from(); // accept if R1 is derived from R2 return false; } class Base { public: virtual ~Base() { } }; class Derived : public Base { }; class Other { }; int _tmain(int argc, _TCHAR* argv[]) { Derived d; Other o; test(d); // OK test(o); // Fails in VC++ 2005 return 0; } 

Los créditos van a http://www2.research.att.com/~bs/bs_faq2.html#constraints

Debo admitir que no veo la motivación detrás de esto, particularmente si requiere escribir una gran cantidad de códigos de apoyo. Para su operador:

 template bool operator==(Manager m1, Manager m2) { return p1.internal_field == p2.internal_field; } 

para comstackr sin una advertencia, ambos tipos de parámetros de plantilla deben ser capaces de ser parámetros de la plantilla de Manager, y esos tipos deben tener miembros privados (supongo que p1 y p2 deben ser m1 y m2) llamados internal_field. Dadas esas limitaciones, ¿cuál es la posibilidad de que esta función de plantilla pueda ser llamada por accidente en el (los) tipo (s) incorrecto (s)?