试图理解重载函数是如何选择的

Trying to understand how an overloaded function is chosen

本文关键字:何选择 选择 重载 函数      更新时间:2023-10-16

我有以下程序:

#include <iostream>
namespace detail {
    template <class T> char test(int T::*)
    {
       std::cout << "Came to onen";
       return 0;
    }
    template <class T> int test(...)
    {
       std::cout << "Came to twon";
       return 0;
    }
}
struct A {};
int main()
{
   detail::test<A>(0);
   detail::test<int>(0);
}

在使用g++ 4.8.2进行测试时,它产生以下输出:<>之前来到了一个到了二之前

我的问题是:为什么第一次调用明确选择detail::test的第一个版本?

在没有details::test的第一个版本的情况下,main的代码编译得很好。当它在那里时,编译器认为它比第二个更适合detail::test<A>()

更新2

在阅读了之后,即使对于不完整类型或没有指定类型的成员,指向成员的指针也是格式良好的。,我试了下面的,它工作。

struct A;
int main()
{
   detail::test<A>(0);
   detail::test<int>(0);
}

c++ 11标准有相当多的地方揭示了我没有想到的概念。

编译器经历了名称查找、参数推导和重载解析的三位一体过程。名称查找发现test的两个重载,并且指向成员的指针的参数推导对于非类类型将失败,但对于不完整类型或缺少成员则不会失败。最后,在可行的候选对象中,重载解析选择最佳匹配(省略号转换为最低等级)。


这里有三个相关的标准引号:

根据8.3.3指向成员的指针[dcl。mptr]/2指向成员的指针即使对于不完整类型或没有指定类型的成员也是格式良好的。

根据14.8.2模板实参演绎[temp. deduction]/8:

如果替换导致无效的类型或表达式,则键入扣除失败。

其中一个例子是:

试图在T不是类时创建"指向T成员的指针"类型。

最后,根据13.3.3.2对隐式转换序列[over.ics]进行排序。省略号(...)重载在重载解析过程中具有所有隐式转换序列中最低的秩:

2在比较隐式转换序列的基本形式(如定义于13.3.3.1)

-一个标准的转换序列(13.3.3.1.1)是比用户定义的转换序列更好的转换序列或省略号转换序列,和

—用户定义的转换序列(13.3.3.1.2)是比省略号更好的转换序列转换序列(13.3.3.1.3).

您的第一个调用detail::test<A>(0);有两个可行的候选者,但它选择了第一个重载,因为它是一个更好的匹配。第二次调用detail::test<int>(0);在第一次重载时产生替换错误,因此选择第二个匹配项。

在本例中,第一个重载比第二个重载被选择,因为就参数转换序列而言,它更适合——省略号转换序列排在最后。