2010-12-15 9 views
13

Sé que aquí me falta algo fácil, pero tengo una función de miembro con plantilla de una clase que he especializado.especialización de plantillas símbolos de multiplicación definida

MyClass 
{ 
    template<typename T> T GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s); 
} 

template<typename T> 
T MyClass::GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    throw std::runtime_error("Don't know how to convert " + ToString(v->GetString())); 
} 

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    return v->GetInteger(); 
} 

template<> 
string MyClass::GetTFromVariable<string>(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    return v->GetString(); 
} 

// etc for other specialisations. 

Esto se define en mi archivo de cabecera (como plantillas deben ser) pero cuando voy y compilar me sale un montón de símbolos mutliply definidos, un error de este tipo representativo es:

 OtCustomZenith_logic.lib(PtPathOutput.obj) : error LNK2005: "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall MyClass::GetTFromVariable<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class boost::shared_ptr<class TOtSimpleVariable>,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" ([email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected]@[email protected]@Z) already defined in TableFareSystem_test.obj 

que pueda arréglelo haciendo hincapié en los métodos, pero no creo que sea necesario ... ¿qué olvidé?

EDIT: Estoy usando Visual Studio 2010

+0

¿Qué cadena de herramientas estás utilizando? GCC? ¿Visual algo? Si GCC, ¿cómo se ven las líneas de compilación y enlace? –

Respuesta

23

Como se ha señalado Alf, la especialización completa ya no es una plantilla. Sin embargo, no estoy seguro de que tenga definido en línea. También debería poder dividir la declaración y la definición.

I.e. En el encabezado de tener:

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s); 

y en la ejecución tienen:

template<> 
int MyClass::GetTFromVariable<int>(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    return v->GetInteger(); 
} 

Yo también había pensado que por derechos de la definición de plantilla también debe ser explícitamente línea (siempre he hecho), pero no estaría demasiado sorprendido si un compilador dado fuera poco aplicado en la aplicación de ODR para las plantillas. Me interesaría ver la referencia estándar que dice lo contrario.

+1

Lamento la redacción impreciso. Solo estaba hablando sobre el código del OP tal como era/se presenta, con la definición en el archivo del encabezado. ¡Gracias por aclararlo! Cheers, –

+0

mover la especialización desde el encabezado a un único archivo .cpp implica la necesidad de compilar y vincular a un .obj o .lib que dañe la usabilidad. es mejor mantenerlo en línea como lo sugiere @alf. Estoy abajo votando tu respuesta debido a esto. –

23

La especialización completa ya no es una plantilla. Es una función concreta. Como tal, debe ser (implícita o explícitamente) declarado inline. Lo más fácil es agregar esa palabra clave antes de la especificación del tipo de devolución.

Dicho esto, el código presentado no corresponde a su mensaje de error.

Su mensaje de error se refiere al tipo de devolución std::string, no al tipo de devolución int.

Saludos & HTH.,

+0

"Su mensaje de error se refiere al tipo de devolución' std :: string', no al tipo de devolución 'int'." ... lo que significa que está usando la primera plantilla (general), que devuelve el tipo T (en este caso, 'std :: string'). –

+1

@Mike: no, significa que el código presentado no coincide con el mensaje de error. podría * adivinar * que el OP tiene varias especialidades explícitas, no solo una, y que seleccionó un mensaje de error arbitrario. pero sería solo una suposición.Lo que digo es que cuando busques ayuda, trata de ser preciso, no introduzcas problemas irrelevantes. –

+0

Gracias @alf, tenías razón y he actualizado la pregunta para reflejar el problema con más precisión. –

2

yo sugeriría que para eliminar la siguiente implementación de su código por completo, de manera que compilador puede generar el error en tiempo de compilación en sí si T no está int. La detección temprana de errores es mejor que la detección de retardos (que se realiza en tiempo de ejecución).

template<typename T> 
T MyClass::GetTFromVariable(shared_ptr<TOtSimpleVariable> v, string s) 
{ 
    throw std::runtime_error("Don't know how to convert " + ToString(v->GetString())); 
} 

Hay exactamente un tema/tema similar discutiendo esto. Por favor, eche un vistazo a esto:

Partial template specialization for specific type, c++

+1

mejor que eliminarlo es dejar esto, pero use static_assert (false, "explicar el problema y la solución"). esto ayudará a los desarrolladores a entender qué es lo que está mal si se produce el error. –

Cuestiones relacionadas