试图了解如何选择重载函数

时间:2014-07-01 05:29:24

标签: c++ templates c++11 g++ overload-resolution

我有以下程序:

#include <iostream>

namespace detail {

    template <class T> char test(int T::*)
    {
       std::cout << "Came to one\n";
       return 0;
    }

    template <class T> int test(...)
    {
       std::cout << "Came to two\n";
       return 0;
    }
}

struct A {};

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

使用g ++ 4.8.2进行测试时,会产生以下输出:

Came to one
Came to two

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

更新

如果没有details::test的第一个版本,main的代码编译得很好。当它存在时,编译器认为它比detail::test<A>()更好地匹配第二个。

更新2

在阅读之后,即使对于不完整的类型或没有指定类型的成员,指向成员的指针也是格式正确的。,我尝试了以下内容并且它可以正常工作。

struct A;

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

C ++ 11标准有很多地方可以发现我不会想到的概念。

2 个答案:

答案 0 :(得分:10)

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


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

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

根据 14.8.2模板参数演绎[temp.deduct] / 8

  

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

列出的众多例子之一是:

  

当T不是类时,尝试创建“指向T成员的指针”   类型。

最后,根据 13.3.3.2对隐式转换序列进行排名[over.ics.rank] ,省略号(...)重载在重载解析期间具有所有隐式转换序列的最低等级: / p>

  

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);在第一次重载时给出了一个替换错误,因此选择了第二次匹配。

答案 1 :(得分:2)

在这个例子中,第一个重载在第二个上被选中,因为就parameter conversion sequences而言,它更适合 - 省略号转换序列排在最后。