2013-05-31 96 views
10

令我惊讶的这个节目在这两个MSCV和GCC编译:方法名称相同,C++模板方法名称++

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++中与返回类型合法不同,或者是编译器只是宽容吗?

回答

10

这一直是合法的C++。

14.5.6/2:

函数模板可以与其他功能模板和与正常(非模板)函数被重载。普通函数与函数模板无关(即从未被认为是专业化),即使它与潜在生成的函数模板专用具有相同的名称和类型。

当使用“template-id”语法(如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; 
} 

这是有道理的,因为模板仍然可以通过使用其他专业,或明确使用<尖括号>。因此,使用非模板函数重载函数模板有点类似于添加明确的特化,但头痛较少。

+0

哇,后者更有趣 - 将记住这一点,谢谢! –