方法名称与C ++中的模板方法名称相同

时间:2013-05-31 20:13:28

标签: c++ templates

令我惊讶的是,这个程序在MSCV和GCC中编译:

class A
{
public:
  int add() { return 0; }
  template<typename T>
  T add() { return T(); }
};

int main() { 
  A a;
  a.add();
  a.add<int>();
  return 0; 
}

显然,由于模板化方法的类型无法推断并且需要明确说明,所以情况并非如此 - 似乎有点阴暗 - 如果它是一个非模板化的方法,显然是不正确的。

我已经尝试使用Google搜索并查看标准的最后草稿,但找不到答案 - 模板方法和普通方法的命名方式相同,只是在C ++中返回类型为legal,或者是编译器只是宽容?

1 个答案:

答案 0 :(得分:12)

这一直是合法的C ++。

14.5.6 / 2:

  

功能模板可以使用其他功能模板和普通(非模板)功能重载。普通函数与函数模板无关(即,它永远不会被认为是特化),即使它与可能生成的函数模板特化具有相同的名称和类型。

使用&#34; template-id&#34;语法如add<int>,只考虑具有足够模板参数的模板函数。因此,a.add<int>()甚至不会查看非模板add是否匹配。

当标识符同时命名普通函数和函数模板时,编译器将尝试推导函数模板的模板参数以获得模板函数特化。然后通过常用的函数重载逻辑比较所有普通函数和所有模板函数特化。 [见13.3.1 / 7。]

在您的示例中,调用a.add()无法推断出模板版本的模板参数T。因此,唯一可行的功能是非模板重载。

还有另一个规则出现在类似的情况下:如果非模板函数和模板函数特化将是一个模糊的重载,非模板函数获胜。 [这条规则在第13.3.3节中,在定义一个函数比一个给定的参数集合比另一个函数更好的定义的中间。]

class B
{
public:
  int f(int n) { return n+1; }

  template<typename T>
  T f(T n) { return n; }
};

int main() {
  B b;
  b.f(1);       // both are viable, non-template wins
  b.f<int>(1);  // only the template is viable
  return 0;
}

这是有道理的,因为该模板仍可供其他专业化使用,或明确使用<尖括号>。因此,使用非模板函数重载函数模板有点像添加显式特化,但会减少头痛。