考虑这个课程:
class Base{
public:
void func(double a) = delete;
void func(int a) const {}
};
int main(){
Base base;
base.func(1);
return 0;
}
使用clang ++编译时,会产生以下错误:
clang++ --std=c++11 test.cpp
test.cpp:22:7: error: call to member function 'func' is ambiguous
base.func(1);
使用g ++,会产生一个警告:
g++ -std=c++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:22:13: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: base.func(1);
为什么这段代码含糊不清?
非静态成员函数,如下:
void func(double); // #1
void func(int) const; // #2
也接受了 隐式对象参数 这被认为是超载分辨率([over.match] / P1)与任何其他论点一样:
过载分辨率是一种机制,用于在给定作为调用参数的表达式列表和可根据调用上下文调用的一组候选函数的情况下选择要调用的最佳函数。最佳函数的选择标准是参数的数量,参数与候选函数的参数类型列表的匹配程度, (对于非静态成员函数)对象与隐式对象参数的匹配程度,以及候选函数的某些其他属性。
在将隐式对象参数合并到成员函数签名之后,编译器会看到两个重载:
void func(Base&, double); // #1
void func(const Base&, int); // #2
并尝试根据调用选择最佳可行功能:
Base base;
base.func(1);
转换自 base
(这是类型的非常数左值 Base
) 至 Base&
有一个 完全符合 等级(直接参考绑定产生一个 身份转换) - 见 表13。转换自 base
至 const Base&
也是一个 完全符合 但是,排名 [over.ics.rank] /p3.2.6 声明 #1
有一个更好的转换顺序:
- S1和S2是参考绑定([dcl.init.ref]),并且引用引用的类型是除了顶级cv限定符之外的相同类型,并且由S2引用的引用引用的类型比由S1引用的引用引用的类型更加cv限定。 。 [例:
int f(const int &);
int f(int &);
int g(const int &);
int g(int);
int i;
int j = f(i); // calls f(int &)
int k = g(i); // ambiguous
现在为第二个参数,从积分prvalue转换 1
至 double
是一个 浮动积分转换 ([conv.fpint]给出一个 转变 秩。另一方面, 1
至 int
是一个 身份转换 这是一个 完全符合 秩。对于这个论点, #2
被认为具有更好的转换顺序([over.ics.rank] /p3.2.2):
- S1的等级优于S2的等级,或者S1和S2具有相同的等级,并且可以通过下面段落中的规则区分,或者,如果不是,[...]
要成功的过载分辨率要求最多存在一个转换序列不同的参数([over.match.best]):
给定这些定义,如果对于所有参数i,ICS,可行函数F1被定义为比另一个可行函数F2更好的函数一世(F1)不是比ICS更差的转换序列一世(F2),然后
- 对于一些论点j,ICSĴ(F1)是比ICS更好的转换序列Ĵ(F2),或者,如果不是,[...]
在这里,ICS0(#1)优于ICS0(#2),但反过来,ICS1(#2)优于ICS1(#1),因此编译器无法在两个重载之间进行选择并检测歧义。
当函数重载时,首先发生重载决策。如果删除的功能是最佳匹配并且被选中,则程序格式错误。
因此,您的程序将产生与以下相同的错误,因为存在从int到double的隐式转换,并且编译器不知道您打算调用哪个函数:
class Base{
public:
void func(double a) {}
void func(int a) const {}
};
因为它 const
修饰语 func(int)
。该 base
实例不是const。 C ++编译器似乎找到了 non-const
方法首先如果实例不是const。然后,编译器发现该方法已被删除。所以编译器发出警告。
尝试删除 const
修饰符,或移动 const
修饰符 func(double)
将摆脱警告。
似乎这个警告与隐式转换无关。即使你调用 func
通过 func((int)(1))
也不好。