我有以下代码:

#include <iostream>

template <typename T>
void f (T) { std::cout << "f(T)" << std::endl; }

template <typename T>
void f (bool) { std::cout << "f(bool)" << std::endl; }

int main ( )
{
    f(true);        // #1 prints f(T)
    f<bool>(true);  // #2 prints f(bool)
}
#1行调用f(T),而#2行调用f(bool)

为什么会这样?选择重载模板函数的规则是什么?

更新

我了解到,在第一次调用中,编译器无法在尝试调用第二个函数时推断出T,因此选择了第一个。

在第二个调用中,第二个功能被认为是在gcc上更好的匹配,而第一个功能是在VS2013下选择的。谁在这里做正确的事?顺便说一下,我仍然对该过程的完整描述感兴趣。

最佳答案

未特化的功能模板也称为基础基本模板。 基本模板可以是专门的。看看在不同情况下会调用哪个的重载规则非常简单,至少在较高级别上如此:

  • 非模板函数是一等公民。与参数类型以及任何功能模板相匹配的普通旧非模板函数将在原本就很好的函数模板上进行选择。
  • 如果没有一等公民可供选择,那么至少要和二等公民一样好,然后再引用功能库模板。根据一组相当合理的说法,选择哪个功能基础模板取决于哪个匹配最合适,并且是“最专业的”(重要说明:“特化”的这种使用与模板特化毫无关系;这只是一个不幸的口语化)奥术规则:
  • 如果很明显有一个“最专业”的函数库模板,那么就会使用它。如果该基本模板恰好专用于所使用的类型,则将使用该特殊化,否则将使用以正确类型实例化的基本模板。
  • 其他(如您的情况)如果“最专业”的函数库模板有联系,则该调用是不明确的,因为编译器无法确定哪个更匹配。 程序员将必须做一些事情才能使调用合格,并说出需要哪个。
  • 如果没有可以匹配的函数库模板,则调用是错误的,程序员将必须修复代码。

  • 如果要自定义函数基础模板并希望该自定义参与重载解析(或者在完全匹配的情况下始终使用),则使其成为普通的旧函数,而不是专门化的函数。并且,如果您确实提供了重载,请避免也提供特化知识。

    上面是 Herb Sutter的this帖子的摘录,在突出显示的项目符号中,您可以看到问题的根源

    编辑

    如果您尝试(不要这样做)在Visual Studio 2012中使用上述代码,则会得到



    here所述,这是因为



    而以下行应归咎于
    f(true);        // #1 prints f(T)
    

    因此答案中的歧义没有保证的解决方案

    07-24 09:45
    查看更多