2012-02-27 13 views
9

¿Es posible definir dos clases diferentes de plantilla (por número de argumentos de plantilla) con el mismo nombre?¿Plantillas de clase con nombres duplicados?

Aquí es lo que estoy tratando de hacer:

namespace MyNamespace 
{ 

template<class TRet> 
class FunctionObject 
{ 
    typedef typename TRet ReturnType; 
    virtual ReturnType const operator()() const = 0; 
}; 


template<class TRet, class TArg0> 
class FunctionObject 
{ 
    typedef typename TRet ReturnType; 
    typedef typename TArg0 FirstArgumentType; 
    virtual ReturnType const operator()(FirstArgumentType const &arg) const = 0; 
}; 

} 

me sale un error mencionar demasiados argumentos de plantilla al final del corchete de cierre de la segunda definición FunctionObject estructura.

Sé que esto se puede hacer en C#, pero no estaba seguro sobre C++. Por favor alguien puede arrojar algo de luz aquí?

+1

¿Qué quiere decir que se puede hacer en C#? C# no tiene plantillas. –

+0

Creo que significan con genéricos en C#. –

+0

Concepto de genéricos en C#. – user460762

Respuesta

11

creo que la especialización parcial haría el truco:

namespace MyNamespace { 

    template<class TRet, class TArg0> 
    class FunctionObject 
    { 
     typedef typename TRet ReturnType; 
     typedef typename TArg0 FirstArgumentType; 
     virtual ReturnType const operator()(FirstArgumentType const &arg) const = 0; 
    }; 

    template<class TRet> 
    class FunctionObject<TRet,void> 
    { 
     typedef typename TRet ReturnType; 
     virtual ReturnType const operator()() const = 0; 
    }; 

} 

También podría comenzar con una plantilla primaria con más de un parámetro.

Creo que C++ 11 sus plantillas variantes permiten que esto sea más ingenioso, pero no he tenido el tiempo para jugar con esto, así que será mejor que se lo de a alguien más para mostrar.

+0

Sí, lo pensé, pero si quiero crear otra clase con tres argumentos de plantilla, entonces tendré que modificar los actuales para incluir argumentos vacíos para los inaplicables. Buena sugerencia, sin embargo. Gracias. – user460762

+0

@ user460762: Sí, tendrá que comenzar con la cantidad máxima de argumentos que desea tratar. Algunas personas lidiaron con esto al confiar en el macro meta hackeo. Pero, como dije, las plantillas variadas harían el truco. – sbi

+1

¿Por qué no definir solo una plantilla de clase y proporcionar un argumento predeterminado para el segundo parámetro de plantilla? – Nawaz

1

creo que algo como esto también funcionará, pero que tienen clases separadas no puede ser lo que buscas:

namespace MyNamespace 
    { 

     class AbstractFunctionObject 
     { 
     //shared functionality here 
     }; 

     template<class TRet> 
     class ConcreteFunctionObjectA : AbstractFunctionObject 
     { 
     typedef typename TRet ReturnType; 
     virtual ReturnType const operator()() const = 0; 
     }; 


     template<class TRet, class TArg0> 
     class ConcreteFunctionObjectB : AbstractFunctionObject 
     { 
     typedef typename TRet ReturnType; 
     typedef typename TArg0 FirstArgumentType; 
     virtual ReturnType const operator()(FirstArgumentType const &arg) const = 0; 
     }; 

    } 
+0

Si bien esto parece posible, también es inútil.¿Para qué sirve una clase base polimórfica vacía? – sbi

+0

No estaría vacío. Si el OP eligió esta imagen de ruta I, movería la funcionalidad que compartirían todas las plantillas variadic a la clase base. Es difícil adivinar intenciones, así que lo dejé en blanco. –

+0

¿Qué podría haber en un Functor, pero 'operator()()' más algunos typedefs? – sbi

5

Creo que se puede hacer que funcione con una plantilla de clase, proporcionando argumento de tipo predeterminado para el segundo parámetro de plantilla como:

struct null_type {}; 

template<class TRet, class TArg0 = null_type> 
class FunctionObject 
{ 
    typedef typename TRet ReturnType; 
    typedef typename TArg0 FirstArgumentType; 

    //both functions here 
    virtual ReturnType const operator()() const = 0; 

    virtual ReturnType const operator()(FirstArgumentType const &arg) const = 0; 
}; 
+3

Tipo de en la dirección correcta, pero no del todo allí. Esto permitirá el uso de la plantilla con uno o dos argumentos, pero en la pregunta original la definición de las dos plantillas parece ser bastante diferente (miembros diferentes, firma diferente para 'operator()') que parece indicar que * specialization * sería el camino a seguir. Comparado con la respuesta de sbi, este tiene la característica agradable de crear un tipo * unique * ('null_type' debe ser único) y así permitir el uso de' void' como el segundo argumento de la especialización de dos argumentos, que es agradable (+1 para eso) –

+0

@David: De hecho, es una falla grave de mi idea. Debería arreglar eso. – sbi

+0

Sin duda una solución inteligente. Solo una cosa a considerar con este enfoque es que cada clase que herede esta clase/estructura tendrá que implementar todos los operadores vacíos/inaplicables. Por lo tanto, es una compensación entre la solución elegante (menos detallada) frente a una menor carga en la implementación futura. – user460762

6

para mostrar solución variadic sugerido por OSE plantilla:

namespace MyNamespace { 

    template<typename...> FunctionObject; 

    template<class TRet, class TArg0> 
    class FunctionObject<TRet,TArg0> 
    { 
     typedef typename TRet ReturnType; 
     typedef typename TArg0 FirstArgumentType; 
     virtual ReturnType const operator()(FirstArgumentType const &arg) const = 0; 
    }; 

    template<class TRet> 
    class FunctionObject<TRet> 
    { 
     typedef typename TRet ReturnType; 
     virtual ReturnType const operator()() const = 0; 
    }; 

} 

Ahora puede agregar especializaciones en el orden que desee, sin modificar las otras plantillas (a menos que el número/tipo de parámetros de la plantilla entren en conflicto).

+0

Sip, '+ 1', porque es más simple que el mío. Si tiene acceso a un compilador que lo admita. – sbi

Cuestiones relacionadas