如果我编译(gcc 4.6.0)并运行此代码:
#include <iostream>
template <typename T> void F(/* const */ T& value) {
std::cout << "T & " << value << std::endl;
}
template <typename T> void F(/* const */ T* value) {
std::cout << "T * " << value << std::endl;
F(*value);
}
int main(int argc, char* argv[]) {
float f = 123.456;
float* pf = &f;
F(pf);
return 0;
}
我得到以下输出:
T * 0x7fff7b2652c4
T & 123.456
如果我取消注释const关键字,我会得到以下输出:
T & 0x7fff3162c68c
我可以将float* pf = &f;
更改为const float* pf = &f;
以再次获得原始输出,这不是问题。
我想了解的是,在使用const修饰符进行编译时,为了非const const T& value
,重载决策考虑const T* value
比float*
更好地匹配?
答案 0 :(得分:3)
在过载解决期间,无需转换的过载超过了需要进行一些转换的过载,即使这些转换很简单。引用C ++ 03标准,[over.match.best](§13.3.3/ 1):
按如下方式定义ICS i (
F
):
- 如果
F
是静态成员函数,则定义ICS 1 (F
),使得ICS 1 (F
)对于任何函数G
,并且对称地,ICS 1 ({{1} })既不比ICS 1 (G
)更好也不差;否则,- 让ICS i (
G
)表示隐式转换序列,它将列表中的 i -th参数转换为的类型i - 可行函数F
的第i个参数。 13.3.3.1定义了隐式转换序列,13.3.3.2定义了一个隐式转换序列比另一个转换序列更好的转换序列或更差转换序列的含义。鉴于这些定义,如果对于所有参数 i ,可行函数
F
被定义为更好函数而不是另一个可行函数F
。 ,ICS i (F1
)转换序列不比ICS i (F2
)差,然后
- 对于某些参数 j ,ICS j (
F1
)是比ICS j 更好的转换序列({{1 }}),或者,如果不是那样,F2
是非模板函数,F1
是函数模板特化,或者,如果不是,F2
和F1
是函数模板特化,F2
的函数模板比F1
的模板更专业,根据14.5中描述的部分排序规则.5.2,或者,如果不是,- 上下文是由用户定义的转换初始化(参见8.5,13.3.1.5和13.3.1.6)以及从
F2
的返回类型到目标类型的标准转换序列(即类型正在初始化的实体)是一个比返回类型F1
到目标类型的标准转换序列更好的转换序列。
当F2
出现时,为了调用带引用的重载,不需要转换 - F1
推导为F2
且参数为{{1} }。但是,为了调用带有指针的重载,const
需要转换为T
才能使所述重载可行。因此,参考的过载获胜。
当然,请注意,如果将float*
更改为float* const&
,则行为将返回到您预期的方式,因为使用指针的重载将不再需要转换。< / p>