Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialisation of function template in another class/namespace?

NOTE: This question is only loosely related to tinyxml, however including details like that may help illustrate the concept better.

I have written a function template that will iterate through a parent XML nodes children, retrieve the value of the child element and then push that child element value to a vector.

The 'retrieve the value' part is also written as a function template:

i.e.

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

There are specialisations for the retrieval part, for returning different types of child element value, e.g. std::string and other custom objects.

i.e.

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

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

This all works perfectly well, however it struck me that this would be very useful to have in a shared function library when dealing with tinyxml files.

Question: Is it possible to declare a function template in one namespace e.g. namespace UtilityFunctions, which doesn't have any knowledge of specific object types like 'MyObject', and then declare and define specialisations of that function template in other namespaces which do have the knowledge of specific object types like 'MyObject'?

My hunch is that it isn't possible, but the concept of having a common function template seems to me to be useful enough for there to be an alternative way of getting close to the functionality I'm looking for...

Apologies if any of the terminology is incorrect or explanation is unclear. I've done a lot of research around this topic (to get to the point of working function template specialisation within the same namespace) but found no definitive answer as yet.

like image 920
Adam Marshall Avatar asked Jan 18 '12 15:01

Adam Marshall


2 Answers

It is not possible to write in one namespace a specialization of a template defined in another namespace (since that would not be specialization of that template, being defined in another namespace it would be a different template).

However it is perfectly OK to extend namespace where template has been originally defined, writing your specialization in totally separate source file.

So here is what you cannot do:

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

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

You can see nice error message for the above at 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;} 
                        ^

Here is what you can do:

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

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

Is there any reason why that would be a problem?

Also, if you delegate the work to a function associated with the object you are reading (either member or free function), you can depend on that function being found via ADL and called. Meaning you should be able to minimize the amount of such specializations like the above.

Here is example:

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;
}

Edited to add an example

like image 151
bronekk Avatar answered Nov 07 '22 07:11

bronekk


Point here is " Every declaration for a template must be placed in the same namespace, just like repeated declarations of any other named entity "

declaration/defining it in different namespace is not valid, for more info please go through the 12th point in FAQ

like image 27
Sadanand Avatar answered Nov 07 '22 08:11

Sadanand