c++函数重载解析(overloading resolution)

编译器为函数调用决定使用哪一种定义时,对函数重载,函数模板,函数模板重载有个决策过程,叫做重载解析(overloading resolution)。

大概过程如下:

1.创建候选函数列表 :编译器会从作用域中收集所有名称匹配的函数。这些函数称为候选函数。包含普通函数和模板函数;

2. 创建可行函数列表:首先从候选函数列表中筛选参数个数相同的函数,然后进一步通过隐式转换和模板实例化创建出可行函数列表;

3. 最后确认是否有可行函数,如果有则匹配最合适的那个,如果没有则调用出错;

举个例子,我想调用:

may('B');

编译器开始寻找和may同名的函数和函数模板,只考虑特征标不考虑返回类型:

void may(int);                              // #1
float may(float, float = 3);                // #2
void may(char);                             // #3
char *may(const char *);                    // #4
char may(const char &);                     // #5
template<class T> void may(const T &);      // #6
template<class T> void may(T *);            // #7

然后从上述候选函数列表中筛选。

首先排除#4和#7,因为int类型无法隐式转换成指针类型。

然后按匹配优先级选择可行函数:

1. 完全匹配,但常规函数优先于模板;

2. 提升转换;

3. 标准转换;

4. 用户定义的转换;

按上面的标准,函数#1优先于函数#2,因为char到int是提升转换,char到float是标准转换

函数#3,#5,#6又优先于函数#1,#2.因为它们是完全匹配

函数#3,#5优先于函数#6,因为常规函数优先于模板

有多个完全匹配的函数时,如何进行下一步的选择?举个例子:

struct blot
{
    int a;
    char b[10];
};

blot ink = {25, "sports"};

recycle(ink);

以下几个都是完全匹配的函数:

void recycle(blot); // #1 blot-to-blot
void recycle(const blot); // #2 blot-to-(const blot)
void recycle(blot &); // #3 blot-to-(blot &)
void recycle(const blot &); // #4 blot-to-(const blot &)

因为被调函数是非const参数,所以非const参数的指针和引用会优先匹配,在函数#3和#4中,会优先选择函数#3。但这个规则不适用于非指针和引用的参数,比如同时只有函数#1和#2的时候,就会出现函数调用二义性报错。

常规函数优先于模板函数,在多个模板函数之间,更具体的模板函数更优先。显示具体化优先与隐式转换的具体化。看下面这个例子:

template <class Type> void recycle (Type t);
template <> void recycle<blot> (blot & t);

recycle(ink); // 第二个函数模板更具体,优先使用

更具体不一定是说显式具体化,而是编译器认为需要执行的类型转换步骤更少。看下面两个模板:

template <class Type> void recycle (Type t); // #1
template <class Type> void recycle (Type *t); // #2

recycle(&ink);

recycle(&ink)与函数#1匹配时,Type被解释为blot*。

recycle(&ink)与函数#1匹配时,Type被解释为blot。

因此两个隐式实例:void recycle<blot*>(blot*)和void recycle<blot>(blot *)会被发送到可执行池。

void recycle<blot>(blot*)会被认为是更具体的。因为在生成过程中,它需要的转换更少。(这里书中原文写的晦涩难懂)

在<<c++ primer plus>>中提到:

作者应该是写错了,更具体的是模板recycle<blot>(blot *),因为从直觉上看,函数#1是用于非指针参数调用,函数#2用于是指针参数调用的。

模板 #2 (template <class Type> void recycle(Type * t);) 更具体,因为它直接匹配指针类型,而模板 #1 (template <class Type> void recycle(Type t);) 需要将传入的指针转换为 Type。因为模板 #2 对于指针类型没有额外的类型转换,编译器会优先选择 #2

用于找出最具体的模板的规则被称为函数模板的部分排序规则(partial ordering rules )。和显式实例一样,这也是 C++98 新增的特性。

非模板参数的匹配:
如果有一个模板与所有非模板参数都匹配,而另一个模板只有部分匹配,则前者更具体。
指针和引用的匹配:
对于指针和引用类型的参数,编译器会尽量选择非指针或引用类型的参数匹配。
函数模板特例化:
特例化的模板会被认为比一般模板更具体。
数组与指针匹配:
如果一个模板参数是数组类型,而另一个是指向数组的指针类型,则指向数组的指针类型更具体。

还可以手动引导编译器调用你想用的函数模板,举个例子:

#include <iostream>

template<class T>
T lesser(T a, T b) // #1
{
    return a < b ? a : b;
}

int lesser(int a, int b) # 2
{
    a = a < 0 ? -a : a;
    b = b < 0 ? -b : b;
    return a < b ? a : b;
}

int main()
{
    using namespace std;
    int m = 20;
    int n = -10;
    double a = 1.0;
    double b = -2.0;

    cout << lesser(m, n) << endl; // #2
    cout << lesser(a, b) << enld; // #1
    cout << lesser<>(m, n) << endl; // #1
    cout << lesser<int>(a, b) << endl; // #1

    return 0;
}
lesser<>(m, n) 中的 <> 指出,编译器应选择模板函数,而不是非模板函数;编译器注意到实参的类型为int ,因此使用 int 替代 T 对模板进行实例化。
  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值