2012-01-18 13 views
5

NOTA: Esta pregunta solo está vagamente relacionada con tinyxml, sin embargo, incluir detalles como este puede ayudar a ilustrar mejor el concepto.Especialización de la plantilla de función en otra clase/espacio de nombres?

He escrito una plantilla de función que iterará a través de uno de los nodos principales XML secundarios, recuperará el valor del elemento hijo y luego insertará el valor del elemento secundario en un vector.

El 'recuperar el valor' parte también escrito como una plantilla de función:

es decir

template <typename Type> 
Type getXmlCollectionItem(
    const char* elementName, TiXmlNode* child, TiXmlNode* parent); 

Hay especializaciones para la parte de recuperación, para el retorno de los diferentes tipos de valor de elemento de niño, por ejemplo std :: string y otros objetos personalizados.

decir

template <> 
std::string getXmlCollectionItem<std::string>(
    const char* elementName, TiXmlNode* child, TiXmlNode* parent); 

template <> 
MyObject getXmlCollectionItem<MyObject>(
    const char* elementName, TiXmlNode* child, TiXmlNode* parent); 

Todo esto funciona perfectamente bien, sin embargo, se me ocurrió que esto sería muy útil disponer de una biblioteca función compartida cuando se trata de archivos TinyXML.

Pregunta: ¿Es posible declarar una plantilla de función en un espacio de nombres, por ej. namespace UtilityFunctions, que no tiene ningún conocimiento de tipos de objetos específicos como 'MyObject', y luego declarar y definir especializaciones de esa plantilla de función en otros espacios de nombres que sí tienen conocimiento de tipos de objetos específicos como 'MyObject'?

Mi corazonada es que no es posible, pero el concepto de tener una plantilla de función común me parece lo suficientemente útil para que haya una forma alternativa de acercarme a la funcionalidad que estoy buscando. ..

Disculpa si alguna de la terminología es incorrecta o si la explicación no está clara. He investigado mucho sobre este tema (para llegar al punto de la especialización de la plantilla de funciones de trabajo dentro del mismo espacio de nombres) pero aún no he encontrado una respuesta definitiva.

+1

Puede usar sobrecargas de funciones ... devolver bool o código de error y pasar un parámetro de salida por referencia. – AJG85

+0

Sí, eso sería mucho más fácil :) –

+0

[Este artículo de Herb Sutter] (http://www.gotw.ca/publications/mill17.htm) sobre la especialización de funciones puede influir en ti ;-) – AJG85

Respuesta

3

No es posible escribir en un espacio de nombres una especialización de una plantilla definida en otro espacio de nombres (ya que no sería especialización de la plantilla, que se define en otro espacio de nombres sería una plantilla diferente).

Sin embargo, está perfectamente bien ampliar el espacio de nombres donde se ha definido originalmente la plantilla, escribiendo su especialización en un archivo fuente totalmente independiente.

Así que aquí es lo que no puede hacer:

namespace A { namespace B { 
    template <typename T> int foo(T) {throw 1;} 
}} 

template <> int A::B::foo(int) {throw 0;} 

Se puede ver el mensaje de error agradable para lo anterior a http://www.comeaucomputing.com/tryitout/

"ComeauTest.c", line 5: error: the initial explicit specialization of function 
      "A::B::foo(T) [with T=int]" must be declared in the namespace 
      containing the template 
    template <> int A::B::foo(int) {throw 0;} 
         ^

Esto es lo que puede hacer:

namespace A { namespace B { 
    template <typename T> int foo(T) {throw 1;} 
}} 

namespace A { namespace B { 
    template <> int foo(int) {throw 0;} 
}} 

¿Hay alguna razón por la que eso sería un problema?

Además, si delega el trabajo en una función asociada con el objeto que está leyendo (ya sea miembro o función libre), puede confiar en que esa función se encuentre mediante ADL y llamada. Lo que significa que debe poder minimizar la cantidad de tales especializaciones como la anterior.

Aquí es ejemplo:

namespace A { namespace B { 
    template <typename T> int bar(T t) {return 0;} 
    template <typename T> int foo(T t) {return bar(t);} 
}} 

namespace C { 
    struct Bah {}; 
    int bar(Bah&) {return 1;} 
} 


int main(int argc,char** argv) 
{ 
    C::Bah bah; 

    std::cout << A::B::foo(0) << std::endl; 
    std::cout << A::B::foo(bah) << std::endl; 
} 

Editado añadir un ejemplo

+0

+1 muy agradable, un cálida bienvenida a bordo de la comunidad SO C++ :) –

1

punto aquí es "Cada declaración para una plantilla debe ser colocada en el mismo espacio de nombres, al igual que las declaraciones repetidas de cualquier otra nombre de la entidad "

declaración/definirla en el espacio de nombres diferente no es válida, para obtener más información, pase por el punto 12 en FAQ

Cuestiones relacionadas