2011-11-02 22 views
5

que tienen una clase base de la plantilla de esta manera:¿Limita una función de plantilla a tipos base y derivados?

template<typename T, std::size_t Size> 
class VectorT 
{ 
public: 
    typedef T data_type; 
} 

y unas cuantas clases derivadas especializados:

template<typename T> 
class Vector2d : public VectorT<T, 2U> 
{ // some specialised functions } 

template<typename T> 
class Vector3d : public VectorT<T, 3U> 
{ // some other specialised functions } 

y estos funcionan bien. Howerver, tengo algunas funciones independientes para los operadores. Por ejemplo:

template<typename T, size_t Size> 
VectorT<T, Size> operator*(T lhs, const VectorT<T, Size>& rhs) 
{ 
    ... 
} 

Lamentablemente, estos no funcionan para mis clases derivadas, ya que devuelven un VectorT<T, Size> en lugar de un Vector2d<T>.

así que traté con

template<V> 
V operator*(typename V::data_type lhs, const V& rhs) 
{ 
    ... 
} 

y esto funciona bien, sin embargo, puede dar lugar a ambigüedades, ya que aspira cualquier otra cosa con un miembro de data_type.

¿Cómo puedo evitar esto: cómo puedo escribir las funciones de tipo seguro que solo funcionan con mi base de vector, o cualquier derivada de?

Estoy tratando de tener que volver a declarar y redefinir los operadores de nuevo para las subclases.

Respuesta

7

Se podría añadir otra clase base, que es independiente de los parámetros de plantilla, y el uso SFINAE desactivar las llamadas para tipos distintos de deriva de dicha base:

struct VectorBase {}; 

template< typename T, std::size_t Size > 
class VectorT : public VectorBase { ... } 

template< typename V > 
typename boost::enable_if< boost::is_base_of< VectorBase, V >, V >::type 
operator*(V lhs, V const& rhs){ ... } 

Tenga en cuenta que is_base_of< X, X > es siempre true, por lo que esta función funcionará para un tipo más que el requerido, a saber, la clase base VectorBase.

Si está utilizando un compilador que implementa TR1, puede reemplazar boost:: por std:: en los dos lugares donde se usa.

+1

Gracias, esta es la segunda vez esta noche que me ha dado una respuesta que involucra SFINAE; ¡Creo que aquí es donde yacen las lagunas en mi conocimiento! No estoy seguro de cómo funciona aún enable_if, pero esto funcionó muy bien. Gracias de nuevo. – DanDan

+0

@Kballo: con respecto a la sustitución de 'boost ::' por 'std ::' -> tenga en cuenta que 'std :: enable_if' es un equivalente estricto para' boost :: enable_if_c', por lo tanto, tendría que "desenvolver" el ' valor' miembro de 'is_base_of' usted mismo cuando se cambia a' std :: '. –

1

Usted se encuentra en una situación inusual, de la cual no existe una forma "agradable". Puede:

  1. Comprobar el tipo en tiempo de ejecución (o tiempo de compilación, probablemente impulso puede hacer eso)
  2. Tome un VectorT<>& y el uso que en lugar de crear una nueva VectorT dentro de la función y devolverlo. De esta forma, puede tomar las subclases de VectorT por referencia también. Sin embargo, eso te obligaría a usar una función en lugar de un operador.
  3. Haz lo que dijo K-ballo.
+1

Me gusta la opción 3 más: P –

Cuestiones relacionadas