请考虑以下代码:

#include <stdio.h>

namespace Foo {
  template <typename T>
  void foo(T *, int) { puts("T"); }

  template <typename T>
  struct foo_fun {
    static void fun() { foo((T *)0, 0); };
  };
}

namespace Foo {
  void foo(int *, int) { puts("int"); }
}

using namespace Foo;

int main() {
  foo_fun<int> fun;
  fun.fun();
}

预期产量是多少? &QUOT; T&QUOT;还是int?

一个编译器(来自Apple的Xcode 3.1.2的gcc 4.0.1)输出“int”,另外两个编译器(gcc 4.1.2和4.1.3)输出“T”。

如果我在foo(T *,int)版本之前移动foo(int *,int)声明/定义,则所有输出都是“int”。在这种情况下,当前标准是否定义了重载/特化的顺序?

有帮助吗?

解决方案

第二个 void foo(... 是一个重载(而不是一个特殊化),它在 foo_fun :: fun 的定义中不可见,所以它赢了“可以在模板定义的上下文中找到。因为 T * 是一个依赖类型, foo 的解析在 foo((T *)0中, 0)将被延迟,直到模板实例化时间和实例化的上下文也将被考虑。但是,标准的14.6.4.2表示如果函数名称是 unqualified-id 但不是 template-id 然后对于非ADL查找,只考虑在模板定义点可见的函数。 Foo 命名空间中没有函数参数所以没有参数依赖查找,因此调用 foo 的模板版本而不是非模板重载。

非常感谢对这个答案进行更正。

如果你使它成为如下的特化,那么在模板实例化时选择特化,只要在首次实例化函数模板时相关的特化是可见的,就可以调用特化。 INT

namespace Foo {
    template<>
    void foo<int>(int *, int) { puts("int"); }
}

当前标准的第14章,但它不是非常易读:)

编辑:如果我必须选择标准中最相关的部分,它可能是14.6 [temp.res]第9段。(稍微缩写)如果名称不依赖于模板参数,该名称的声明应在名称出现在模板定义中的范围内;该名称绑定到此时发现的声明,并且此绑定不受在实例化时可见的声明的影响。

编辑,编辑:但您还需要考虑14.6.4.2 [temp.dep.candidate]。由于所有的相互依赖性,尝试引用标准是非常困难和危险的,这个答案就是一个很好的例子。

其他提示

作为一般规则,在两个版本的编译器中,后者更可能更标准。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top