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

Specialisation of function template in another class/namespace?

本文关键字:专业化 命名空间 另一个 函数模板      更新时间:2023-10-16

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

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

"检索值"部分也被写成一个函数模板:

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'等特定对象类型没有任何了解,然后在其他命名空间中声明和定义该函数模板的专业化,这些命名空间对'MyObject'等特定对象类型有了解

我的直觉是这是不可能的,但在我看来,拥有一个通用功能模板的概念足够有用,可以有一种替代方式来接近我正在寻找的功能。。。

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

在一个命名空间中写入是不可能的是在另一个命名空间中定义的模板的专门化(因为这不是该模板的专业化,在另一命名空间中定义它将是不同的模板)。

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

因此,以下是您不能做的事情:

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

编辑以添加示例

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

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