4

考虑以下代码:

#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();
}

预期的输出是多少?“T”还是整数?

一个编译器(来自 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”。在这种情况下,重载/专业化的顺序是否由当前标准定义?

4

2 回答 2

9

第二个void foo(...是重载(而不是特化),它在定义中不可见,foo_fun::fun因此不会在模板定义的上下文中找到。因为T*是依赖类型,foo表达式中的解析foo((T*)0, 0)将延迟到模板实例化时间,并且实例化的上下文也将被考虑。但是,标准的 14.6.4.2 规定,如果函数名称是非限定 ID而不是模板 ID,则对于非 ADL 查找,仅考虑在模板定义点可见的函数。命名空间中没有函数参数,Foo因此不会发生依赖于参数的查找,因此模板版本foo被调用而不是非模板重载。

非常感谢 litb 对此答案的更正。

如果您将其设为如下特化,则由于在模板实例化时选择了特化,因此只要相关特化在函数模板第一次实例化时可见,就可以调用特化int

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

当前标准的第 14 章,但可读性不强:)

Edit: If I had to pick the most relevant part of the standard it would probably be 14.6 [temp.res] para 9. (Slightly abbreviated) If a name does not depend on a template-parameter, a declaration for that name shall be in scope at the point at where the name appears in the template definition; the name is bound to the declaration found at that point and this binding is not affected by declarations that are visible at the point of instantiation.

Edit, edit: But you also need to take into account 14.6.4.2 [temp.dep.candidate]. It is very difficult and dangerous to try and reference the standard because of all the interdependencies, this answer is a case in point.

于 2008-12-31T20:16:37.800 回答
0

As a general rule, of two versions of a compiler, the later is more likely to be more standard.

于 2008-12-31T20:30:16.743 回答