español - C++ especialización de la función de plantilla dentro de la clase de plantilla
template c++ español (6)
¿Cuál es la sintaxis de C ++ para especializar una función de plantilla que está dentro de una clase de plantilla? Por ejemplo, considere que tengo las siguientes dos clases y su uso. Me gustaría poder proporcionar implementaciones especializadas del método X :: getAThing () para diferentes tipos. Ej .: int, std :: string, puntero arbitrario o 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 durante al menos una hora, y no puedo encontrar nada que compile. Cualquier ayuda sería muy apreciada!
AFAIK (y los expertos en normas pueden corregirme), no puede especializar una función de plantilla de una clase sin especializarse en la propia clase ...
Es decir, creo que lo siguiente funcionará:
template <> template <> int X<Y>::getAThing<int>(std::string param) {
return getIntThing(param); // Some function that crunches on param and returns an int.
}
C ++ no tiene ningún concepto de especialización parcial para las plantillas de funciones. Sin embargo, puede obtener el mismo efecto que la especialización completa a través de la sobrecarga de funciones.
Supongo que tienes algo como esto, que es realmente una de las únicas formas de hacerlo.
template<class TYPE>
class MyInterface {
public:
template<class RETURN>
RETURN myFunction(RETURN& ref, ....);
};
En este caso, especializa "myFunction ()" declarando funciones miembro ordinarias con el tipo deseado. Las reglas de sobrecarga de funciones de C ++ deberían proporcionarle lo que desea, 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 función "std :: string" cuando corresponda, y nunca podrá utilizar la plantilla interna.
Esta es la forma más sencilla y 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
}
Para los curiosos, esta es probablemente la solución a la que iré en mi propio código. Esta es una ligera variación en la respuesta de , que elimina la necesidad de una clase extra. Todavía le doy utilería a , ya que él hizo la mayor parte del trabajo en las piernas:
#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;
}
Por lo tanto, estoy tomando un enfoque diferente para responder a su pregunta. Voy a empezar desde algo que hace lo que quieres y funciona. Y entonces tal vez podamos descubrir cómo permutarlo en algo más cercano a lo que realmente quieres:
#include <string>
#include <iostream>
int getIntThing(const ::std::string ¶m);
template <typename returnT>
returnT getThingFree(const ::std::string ¶m);
template <>
int getThingFree<int>(const ::std::string ¶m)
{
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 funciona, y no es exactamente lo que quieres, pero está más cerca. Creo que lo has pensado tú mismo. También es bastante feo en la forma en que usa la deducción de tipos.
#include <string>
#include <iostream>
template <class c1> class X;
int getIntThing(const ::std::string ¶m)
{
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 ¶m,
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 ¶m) {
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 ¶m) {
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'';
}
Recomendaría declarar getThingFunctor
y friendlyGetThing
en un espacio de nombres de utilidad semi-privado.
Tratar
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 que tú.
Creo que no puedes especializar a los miembros en masa. Debe especificar una especialización particular de la plantilla de clase antes de poder comenzar a especializar a sus miembros.