我对类型T
和const T&
的参数的c ++函数匹配有疑问。
假设我有以下两个函数:
void f(int i) {}
void f(const int &ri) {}
如果我使用f
类型的参数调用const int
,那么此调用当然是不明确的。但是为什么f
对int
类型的参数的调用也不明确? f
的第一个版本不是完全匹配而第二个版本不匹配,因为int
参数必须转换为const int
吗?
const int ci = 0;
int i = 0;
f(ci); // of course ambiguous
f(i); // why also ambiguous?
我知道这种重载没有多大意义,因为f
的调用几乎总是不明确的,除非参数类型T没有可访问的复制构造函数。但我只是研究功能匹配的规则。
此致 凯文
编辑:让我的问题更清楚。如果我有两个功能:
void f(int *pi) {}
void f(const int *pi) {}
然后以下调用不明确:
int i = 0;
f(&i); // not ambiguous, first version f(int*) chosen
虽然可以使用f
调用&i
的两个版本,但是选择了第一个版本,因为f
的第二个版本将包含到const.
的转换,即第一个版本是“更好的匹配”。但在两个功能中:
void f(int i) {} and
void f(const int &ri) {}
由于某种原因,这种对const
的额外转换似乎被忽略了。同样,f
的两个版本都可以使用int
进行调用。但同样,f
的第二个版本需要转换为const
,这会使其与第一个版本f(int).
int i = 1;
// f(int) requires no conversion
// f(const int &) does require a const conversion
// so why are both versions treated as "equally good" matches?
// isnt this analogous to the f(int*) and f(const int*) example?
f(i); // why ambiguous this time?
答案 0 :(得分:3)
一个调用涉及“左值到右值转换”,另一个调用需要身份转换(用于引用)或“资格调整”(用于指针),并且根据标准,这些被同等对待重载决议。
因此,基于不同的转换,两者都不是更好。
然而,标准第13.3.3.2节中有一条特殊规则,只有在被比较的两个候选人都通过参考获取参数时才适用。
如果......
S1
和S2
是参考绑定(8.5.3),则标准转换序列S1
是比标准转换序列S2
更好的转换序列,并且引用引用的类型与顶级 cv-qualifiers 相同,类型相同,S2
引用的引用引用的类型更多 cv-qualified 比S1
初始化的引用所引用的类型。
指针有一个相同的规则。
因此编译器会更喜欢
f(int*);
f(int&);
在
f(const int*);
f(const int&);
分别对f(int)
vs f(const int)
vs f(const int&)
没有偏好,因为左值到右值的转换和资格调整都被视为“完全匹配”。
同样相关,来自第13.3.3.1.4节:
当引用类型的参数直接绑定到参数表达式时,隐式转换序列是标识转换,除非参数表达式的类型是参数类型的派生类,在这种情况下隐式转换序列是派生到基础的转换。
答案 1 :(得分:1)
第二个电话f(i)
也不明确,因为void f(const int &ri)
表示ri
是对i
的引用,并且是一个常量。这意味着它不会修改传递给该函数的原始i
。
是否修改传递的参数的选择权在函数的实现者手中,而不是客户程序员使用该函数。
答案 2 :(得分:0)
第二个调用f(i)不明确的原因是因为对编译器来说,这两个函数都是可以接受的。 const-ness不能用于重载函数,因为函数的不同const版本可以用于单个原因。所以在你的例子中:
int i = 0;
fi(i);
编译器如何知道您打算调用哪个函数? const限定符仅与函数定义相关。
有关更详细的说明,请参阅const function overloading。