另一个类/命名空间中的函数模板的专业化?

时间:2012-01-18 15:10:56

标签: c++ templates template-specialization tinyxml

注意:这个问题只与tinyxml松散相关,但是包含这样的细节可能有助于更好地说明这个概念。

我编写了一个函数模板,它将遍历父XML节点子节点,检索子元素的值,然后将该子元素值推送到向量。

&#39>检索价值' part也写成函数模板:

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

检索部分有专门化,用于返回不同类型的子元素值,例如: std :: string和其他自定义对象。

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

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

这一切都运行得很好,但是让我感到震惊的是,在处理tinyxml文件时,这对于共享函数库非常有用。

问题:是否可以在一个名称空间中声明一个功能模板,例如namespace UtilityFunctions,它不具备'MyObject'等特定对象类型的任何知识,然后在具有特定对象类型知识的其他命名空间中声明和定义该函数模板的特化,如{ {1}}?

我的预感是,这是不可能的,但是在我看来,拥有一个通用功能模板的概念是足够有用的,可以有另一种方法来接近我正在寻找的功能为...

如果任何术语不正确或解释不清楚,请道歉。我已经围绕这个主题做了很多研究(为了达到在同一名称空间内工作的函数模板专业化)但是还没有找到明确的答案。

2 个答案:

答案 0 :(得分:5)

无法在一个命名空间中编写 在另一个命名空间中定义的模板的特殊化(因为那不是该模板的特化,在另一个命名空间中定义命名空间它将是一个不同的模板)。

然而,在最初定义模板的地方扩展命名空间,在完全独立的源文件中编写专业化是完全可以的。

所以这是你不能做的事情:

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

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

您可以在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;} 
                        ^

以下是可以做的事情:

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

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

有什么理由可以解决这个问题吗?

此外,如果将工作委托给与您正在阅读的对象(成员或自由函数)相关联的函数,则可以依赖于通过ADL找到并调用的函数。这意味着您应该能够最大限度地减少上述此类专业化的数量。

以下是示例:

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

已编辑以添加示例

答案 1 :(得分:1)

这里指出的是“模板的每个声明必须放在同一个名称空间中,就像重复声明任何其他命名实体一样”

声明/在不同的命名空间中定义它是无效的, 欲了解更多信息,请查看FAQ

中的第12点