5

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

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

'retrieve the value' 部分也写成函数模板:

IE

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

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

IE

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',然后在其他知道特定对象类型的命名空间中声明和定义该函数模板的特化喜欢'MyObject'

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

如果任何术语不正确或解释不清楚,我们深表歉意。我围绕这个主题做了很多研究(为了达到在同一个命名空间内工作的功能模板专业化的点),但还没有找到明确的答案。

4

2 回答 2

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

编辑添加示例

于 2012-01-18T15:28:37.697 回答
1

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

在不同的命名空间中声明/定义它是无效的,有关更多信息,请查看常见问题解答中的第 12 点

于 2012-01-18T15:41:02.447 回答