¿Cuál es la sintaxis de C++ para que se especializa en una función de la plantilla que está dentro de una clase de plantilla? Por ejemplo, considere la posibilidad de que tengo las dos clases siguientes y su uso. Me gustaría ser capaz de proporcionar implementaciones especializadas del método X::getAThing() para los diferentes tipos. E. g.: int, std::string, arbitraria puntero o de clase, etc.

template <class c1> class X {
public:
   template<typename returnT> returnT getAThing(std::string param);
   static std::string getName();
private:
   c1 theData;
};

//This works ok...
template <class c1> std::string X<c1>::getName() {
   return c1::getName();
}

//This blows up with the error:
//error: prototype for 'int X<c1>::getAThing(std::string)' does not match any in class 'X<c1>'
template <class c1> template <typename returnT> int X<c1>::getAThing(std::string param) {
   return getIntThing(param); //Some function that crunches on param and returns an int.
}

//More specialized definitions of getAThing() for other types/classes go here...

class Y {
public:
   static std::string getName() { return "Y"; }
};

int main(int argc, char* argv[])
{
   X<Y> tester;
   int anIntThing = tester.getAThing<int>(std::string("param"));
   cout << "Name: " <<  tester.getName() << endl;
   cout << "An int thing: " << anIntThing << endl;
}

He estado tratando de adivinar la sintaxis correcta para la especialización de al menos una hora, y no puedo entender nada de lo que va a compilar. Cualquier ayuda sería muy apreciada!

InformationsquelleAutor Ogre Psalm33 | 2011-02-14

6 Comentarios

  1. 6

    Así, me estoy tomando un enfoque diferente para responder a tu pregunta. Voy a empezar por algo que de alguna manera hace lo que quiere, y funciona. Y entonces tal vez podamos averiguar cómo permutar en algo más cercano a lo que realmente quieres:

    #include <string>
    #include <iostream>
    int getIntThing(const ::std::string &param);
    template <typename returnT>
    returnT getThingFree(const ::std::string &param);
    template <>
    int getThingFree<int>(const ::std::string &param)
    {
    return getIntThing(param);
    }
    //More specialized definitions of getAThing() for other types/classes
    //go here...
    template <class c1> class X {
    public:
    template<typename returnT> returnT getAThing(std::string param);
    static std::string getName();
    private:
    c1 theData;
    };
    //This works ok...
    template <class c1> std::string X<c1>::getName() {
    return c1::getName();
    }
    //This also works, but it would be nice if I could explicitly specialize
    //this instead of having to explicitly specialize getThingFree.
    template <class c1>
    template <class RT>
    RT X<c1>::getAThing(std::string param) {
    //Some function that crunches on param and returns an RT.
    //Gosh, wouldn't it be nice if I didn't have to redirect through
    //this free function?
    return getThingFree<RT>(param);
    }
    class Y {
    public:
    static std::string getName() { return "Y"; }
    };
    int main(int argc, char* argv[])
    {
    using ::std::cout;
    X<Y> tester;
    int anIntThing = tester.getAThing<int>(std::string("param"));
    cout << "Name: " <<  tester.getName() << '\n';
    cout << "An int thing: " << anIntThing << '\n';
    }

    Aquí hay otra idea que tipo de obras, y no es exactamente lo que quiere, pero está más cerca. Creo que has pensado en ti mismo. Además de ser bastante feo en la forma en que se utiliza el tipo de deducción.

    #include <string>
    #include <iostream>
    template <class c1> class X;
    int getIntThing(const ::std::string &param)
    {
    return param.size();
    }
    //You can partially specialize this, but only for the class, or the
    //class and return type. You cannot partially specialize this for
    //just the return type. OTOH, specializations will be able to access
    //private or protected members of X<c1> as this class is declared a
    //friend.
    template <class c1>
    class friendlyGetThing {
    public:
    template <typename return_t>
    static return_t getThing(X<c1> &xthis, const ::std::string &param,
    return_t *);
    };
    //This can be partially specialized on either class, return type, or
    //both, but it cannot be declared a friend, so will have no access to
    //private or protected members of X<c1>.
    template <class c1, typename return_t>
    class getThingFunctor {
    public:
    typedef return_t r_t;
    return_t operator()(X<c1> &xthis, const ::std::string &param) {
    return_t *fred = 0;
    return friendlyGetThing<c1>::getThing(xthis, param, fred);
    }
    };
    template <class c1> class X {
    public:
    friend class friendlyGetThing<c1>;
    template<typename returnT> returnT getAThing(std::string param) {
    return getThingFunctor<c1, returnT>()(*this, param);
    }
    static std::string getName();
    private:
    c1 theData;
    };
    //This works ok...
    template <class c1> std::string X<c1>::getName() {
    return c1::getName();
    }
    class Y {
    public:
    static std::string getName() { return "Y"; }
    };
    template <class c1>
    class getThingFunctor<c1, int> {
    public:
    int operator()(X<c1> &xthis, const ::std::string &param) {
    return getIntThing(param);
    }
    };
    //More specialized definitions of getAThingFunctor for other types/classes
    //go here...
    int main(int argc, char* argv[])
    {
    using ::std::cout;
    X<Y> tester;
    int anIntThing = tester.getAThing<int>(std::string("param"));
    cout << "Name: " <<  tester.getName() << '\n';
    cout << "An int thing: " << anIntThing << '\n';
    }

    Yo recomendaría declarar getThingFunctor y friendlyGetThing en un semi-privado de la utilidad del espacio de nombres.

    • Este es probablemente el único enfoque con alguna posibilidad de éxito. He probado con un entramado de ayudante de clase, ya que las reglas para la especialización de clase son diferentes de las funciones, pero no la alegría. Nit: ¿no que el último comentario de «ser Más especializados definiciones de getThingFree«, y también tienen que ir arriba?
    • Voigt – Su nit es observado y cuidado. 🙂
    • Wow, yo estaba esperando que el idioma no me obligues a hacer algo tan repulsivo. Como he dicho en otra parte, sería agradable no tener que especializarse cada combinación de clase c1 y returnT.
    • Psalm33 – Así que, va a la aplicación de getAThing necesitan tener acceso a la parte privada de class X<c1>?
    • así, mirando a mi «real» de la aplicación, es en la actualidad el acceso a los miembros protegidos, pero estoy pensando que podría mover la aplicación y llevar a cabo la dependencia de los miembros protegidos así.
    • Ok, eso es francamente feo y horrible buscando (hablando de la sintaxis de C++ gimnasia, no el código :-), pero creo que puedo usar una ligera variación en el functor solución para conseguir lo que quiero. Gracias!
    • Psalm33 – estoy de acuerdo, la gimnasia requiere son bastante feo. Me parece que el conjunto de restricciones sobre lo que está permitido y no permitido ser un poco extraño. Ellos no parecen tener ninguna rima o razón por la que puedo detectar.

  2. 18

    AFAIK (y los expertos en normas pueden corregirme), usted puede especializarse en una función de plantilla de una plantilla de clase sin especializada de la misma clase…

    es decir, el siguiente creo que va a funcionar:

    template <> template <> int X<Y>::getAThing<int>(std::string param) {
    return getIntThing(param); //Some function that crunches on param and returns an int.
    }
    • Acabo de llegar a la misma conclusión.
    • Los mensajes de error que me gcc indican que probablemente la correcta. Aunque es difícil de decir ya que las plantillas a menudo conducen a los extraños y misteriosos mensajes de error. Y en realidad, prueba de que en el gcc, de hecho, el trabajo. Yo diría que tienes razón, aunque para encontrar exactamente donde la norma dice que es un negocio interesante.
    • Yo sé lo que quieres decir, yo estaba perplejo por esto por alrededor de una hora hoy: expected primary-expression before ‘>’!?! resulta que me faltaba la palabra clave template en una llamada a una función de plantilla dentro de una plantilla de clase, ahora usa la extraña sintaxis: some_obj.template foo<bar>(); – wtf? el que pensó que era una idea inteligente?!?
    • Ick, que es lo que me temía.
    • 14.7.3p18: «En una explícita especialización declaración de un miembro de una plantilla de clase o un miembro de la plantilla que aparece en el ámbito de espacio de nombres, el miembro de la plantilla y algunos de su clase envolvente plantillas pueden permanecer no especializada, salvo que la declaración no explícitamente se especializan en un miembro de la clase de plantilla si su clase envolvente plantillas no están explícitamente especializados así.»
    • Creo que tengo un buen conocimiento de inglés, pero declaraciones como que, que hacen que mis ojos se ejecute, la razón por la que he evitado leer las normas…

  3. 8

    C++ no tiene ningún concepto parcial de especialización para la función de las plantillas. Sin embargo, usted puede conseguir el mismo efecto completo de la especialización a través de la sobrecarga de funciones.

    Estoy asumiendo que tener algo como esto, que en realidad es una de las únicas formas de hacerlo.

    template<class TYPE>
    class MyInterface {
    public:
    template<class RETURN>
    RETURN myFunction(RETURN& ref, ....);
    };

    En este caso, se especializan «myFunction()» declarando miembro ordinario de las funciones con el tipo deseado. C++de la función de sobrecarga reglas deben dar lo que usted quiere, por ejemplo,

    template<class TYPE>
    class MyInterface {
    public:
    template<class RETURN>
    RETURN myFunction(RETURN& ref, ....);
    //String specialization
    std::string myFunction(std::string& ref, ...);
    };

    El compilador utilizará la «std::string» función de donde proceda, y nunca podrá usar la plantilla interna en absoluto.

    • Buena solución para un pequeño conjunto de tipos, upvoted.
    • No creo que esto funciona para los no-tipo de argumentos de plantilla.
  4. 1

    Para los curiosos, esta es probablemente la solución que voy a ir en mi propio código. Esta es una ligera variación en Omnifarious‘s respuesta, que elimina la necesidad de una clase extra. Todavía puedo dar mi apoyo a Omnifarious, como hizo la mayoría del trabajo de la pierna:

    #include <iostream>
    #include <string>
    using namespace std;
    //IMPORTANT NOTE: AdaptingFunctor has no access to the guts of class X!
    //Thus, this solution is somewhat limited.
    template<typename t1> class AdaptingFunctor {
    public:
    t1 operator() (string param);
    };
    //Can specialize AdaptingFunctor for each type required:
    template<> int AdaptingFunctor<int>::operator() (string param)
    {
    return param.size(); //<=== Insert required type-specific logic here
    }
    //Additional specializations for each return type can go
    //here, without requiring specialization of class c1 for X...
    template <class c1> class X {
    public:
    template<typename returnT>  returnT getAThing(std::string param)
    {
    AdaptingFunctor<returnT> adapter;
    return adapter(param);
    }
    static std::string getName();
    private:
    c1 theData;
    };
    //Template definition of class method works ok...
    template <class c1> std::string X<c1>::getName() {
    return c1::getName();
    }
    class Y {
    public:
    static std::string getName() { return "Y"; }
    };
    int main(int argc, char* argv[])
    {
    X<Y> tester;
    int anIntThing = tester.getAThing<int>(std::string("param"));
    cout << "Name: " <<  tester.getName() << endl;
    cout << "An int thing: " << anIntThing << endl;
    }
  5. -1

    Intentar

    template <>
    template <class T>
    int X<T>::template getAThing<int>(std::string param)
    {
    return getIntThing(param);
    }

    Esto todavía no se compila, pero está más cerca de lo que había.

    Creo que no se especializan miembros en masa. Usted tiene que especificar un particular especialización de la plantilla de clase antes de empezar especializada de sus miembros.

    • Aunque yo no la prueba, pero esto parece correcto!
    • He intentado esto, y no me funciona con gcc 4.5.
    • Lo que si se invierte el orden de la plantilla de soportes? es decir template <class T> template<> lugar. Tiene más sentido, ya que la función de la plantilla está dentro de la clase de plantilla, por lo que la declaración de la plantilla debe estar anidada dentro de la clase. Vale la pena intentarlo.
    • Kondratskiy – he intentado. Todavía no funciona. Muy diferente de error, aunque. 🙂
    • Hmmm, interesante pensamientos. Sí, si tengo que especializar la función de ambos (por ejemplo) clase y tipo int, que me deja con una gran cantidad de posibles combinaciones de funciones para definir. Si su corazonada es correcta Ben, voy a tener que dejar atrás a hacer algo como la implementación de getAThing() usando un dispositivo de functor de clase, y se especializan que, para los casos donde getAThing()’s definición no depende de la info de la clase c1.
    • Esto no tiene ningún sentido. ‘X’ que se está especializada con ‘T’ de una plantilla anidada parámetro. El tipo de ‘X<T>’ no está relacionado con el principal original de la plantilla y no tiene definición y no miembros. Como ‘getAThing’ no es un miembro de la clase que no se especializan en esa clase.
    • Estás equivocado acerca de X<T> ser un vacío de especialización. La razón de esta falla es que primero tiene que especializar la clase antes de especializarse en un miembro, y esto no. Pero ya que insisten en downvoting, siento libre.
    • Yo abajo votado porque aparte de que el hecho de que su ejemplo es ilegal demasiado, no creo que sea útil. En el otro punto, tienes razón – me equivoqué al decir que ‘X<T>’ es un vacío de la especialización. Después de pensarlo un poco más – ‘X<T>’ no es simplemente un sensato construir y por lo que realmente no tiene ningún sentido en absoluto.
    • Usted puede mirar en cualquier ejemplo de implementación de la clase de los miembros de una clase de plantilla, que es perfectamente legal, y utiliza template <class T>X<T>:: en dicha forma. Ese no es el tema aquí. El problema con el OP del diseño es que C++ requiere que se especializa la clase antes de especializarse miembros, si ese requisito no existe, esta sería la sintaxis correcta.
    • Entiendo que el problema de la OP. Respecto a su comentario de los miembros de la clase, cuando se utiliza ‘T’ donde ‘T’ es una plantilla anidada parámetro con una mayor actividad de anidación de la plantilla de tu especializada, a continuación, es una cosa diferente. TBH – creo que podemos estar de acuerdo para diferir.

  6. -2

    Aquí la más simple es la forma más fácil que he visto hasta ahora para hacer esto:

    template <class T1>
    struct MyClass {
    template <class T2>
    void MyFunction();
    };
    template <class T1>
    template <class T2>
    void MyClass<T1>::MyFunction() {  //NOTE:  NO T2 on this line.
    //Code goes here
    }
    • El OP quiere que cada uno de T2, el uso de otro cuerpo de la función (en el sentido sintáctico). Su ejemplo se utiliza el mismo cuerpo de la función para todos los tipos de T2.
    • Richard Corden es correcta. Queríamos ser capaces de especializarse MyFunction del cuerpo para muchos diferentes tipos o clases, donde (y esta es la parte importante) T2 puede ser cualquier tipo básico.

Dejar respuesta

Please enter your comment!
Please enter your name here