【问题标题】:C++ template functions overload resolutionC++ 模板函数重载决议
【发布时间】:2014-04-20 03:02:46
【问题描述】:

我有以下代码:

#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 下选择的。谁在这里做正确的事?顺便说一句,我仍然对过程的完整描述感兴趣。

【问题讨论】:

  • 不知道规则,但我看不出编译器如何在你的第二个模板中推断出T,所以我看不出如果没有明确的参数如何选择它。 (但同样,我对模板细节一无所知。)

标签: c++ templates overloading overload-resolution


【解决方案1】:

未特化的函数模板也称为基础基础模板。基础模板可以是特化的。查看哪些在不同情况下被调用的重载规则非常简单,至少在高层次上是这样:

  • 非模板函数是一等公民。与参数类型以及任何函数模板相匹配的普通旧非模板函数将被选择,而不是其他情况相同的函数模板。

  • 如果没有至少一样好的一等公民可供选择,那么接下来咨询二等公民的功能基本模板。选择哪个函数基模板取决于哪个匹配最好并且是“最专业的”(重要说明:奇怪的是,“专业”的这种使用与模板专业化无关;这只是一种不幸的口语)根据一组公平神秘的规则:

    • 如果很明显有一个“最专业”的函数基础模板,那么就会使用那个模板。如果该基本模板恰好专门用于正在使用的类型,则将使用该专门化,否则将使用使用正确类型实例化的基本模板。

    • 否则(如您的情况)如果“最专业”的函数基本模板存在相同的情况,则调用不明确,因为编译器无法确定哪个更匹配. 程序员必须做一些事情来限定调用并说出需要哪个调用。

    • 否则,如果没有可匹配的函数基模板,则调用错误,程序员将不得不修复代码。

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

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

编辑

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

致命错误 LNK1179:无效或损坏的文件:重复 COMDAT '??$f@_N@@YAX_N@Z'

正如here 解释的那样,这是因为

你做了一些无效 C++ 的“诡计”,它通过了编译器,但你现在有一个无效的 *.obj,它阻塞了链接器。

下面这行是罪魁祸首

f(true);        // #1 prints f(T)

所以答案中解释的歧义没有保证解决

【讨论】:

  • 您可能想感谢 Herb Sutter 的摘录,参见。 gotw.ca/publications/mill17.htm.
  • 那么,第二个调用是歧义?第一个电话是怎么回事?
  • Herb 的解释我已经看了好几遍了,还是不明白。我认为这取决于“最专业”的含义。有人会认为 f(bool) 更专业,但显然不是,无论在什么意义上,这里使用了“专业”。我不明白的第二件事是 f(true) 和 f(true) 之间存在区别,因为 T 在第一种情况下也必须是布尔值。
  • 基本模板都是模板,它们都不是专门化的(注意重要提示:奇怪的是,这种“专门化”的使用与模板专门化无关)胜任、有资格、能干的话会更清楚。首先选择基本模板,然后我们继续进行规范化。在这种情况下,基本模板的选择是不明确的
  • @lisyarus 很抱歉,但我仍然不明白为什么调用 "f(true); // #1 prints f(T)" 是模棱两可的?它应该是带有 "f(true); // #2 打印 f(bool)" 的那个吗?由于在 #1 中无法为第二个函数模板推导出 T,因此第一个函数模板是完美匹配的。但是对于#2,就很模糊了。我错过了什么?
【解决方案2】:

实际上你想要的是一个模板专业化,在你的情况下,应该这样写:

template<> // Without any typename in it!
void f (bool) { std::cout << "f(bool)" << std::endl; }

这在 VS2012 中按预期工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    相关资源
    最近更新 更多