哪种编译器适用于以下重载/特化行为?

时间:2008-12-31 19:57:58

标签: c++ standards specialization overloading

请考虑以下代码:

#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”或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”。在这种情况下,当前标准是否定义了重载/特化的顺序?

2 个答案:

答案 0 :(得分:9)

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

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

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

int

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

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

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

答案 1 :(得分:0)

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