让我们考虑以下示例:
#include <type_traits>
#if 1
struct X {};
struct O
{
O(X) { ; }
};
#else
struct O {};
struct X
{
operator O () { return {}; }
};
#endif
static_assert(std::is_convertible< X, O >::value);
struct S
{
void f(X) const { ; }
void f(O) { ; }
};
#include <cstdlib>
int
main()
{
S s;
s.f(X{});
return EXIT_SUCCESS;
}
它出错了:
error: call to member function 'f' is ambiguous
当我删除const
- 限定符时,错误就不复存在了。如果我将const
- 限定符添加到f
的第二次重载,同样会发生同样的情况。即如果两个重载都相同const
- 合格,则一切正常。
为什么会这样?
我的编译器是 clang 3.8 。
答案 0 :(得分:2)
Why is it so?
:这里的原因是因为s
对象本身的常量在重载决策中也是 。由于s
是非const,因此需要将const添加到隐式this
指针以调用const f
。调用非const f
与this
指针完全匹配,但需要通过O的转换构造函数从X
隐式转换为O
。
答案 1 :(得分:2)
成员函数具有隐式参数this
。
因此,要调用其中一个函数f
,编译器需要将this
转换为const S *
类型或将X
转换为O
。
关于所有参数的转换都不是更好。所以编译器发出错误。
答案 2 :(得分:1)
马克B &amp; Vlad来自莫斯科回答为什么,我只是回复你怎么称呼他们。
你应该添加explicit
以避免编译器隐式转换
#include <iostream>
struct X {};
struct O
{
explicit O(X) { ; }
O() = default;
O(O const &) = default;
O(O &&) = default;
};
struct S
{
void f(X) const { ; }
void f(O) { ; }
};
#include <cstdlib>
int main()
{
S s;
s.f(X{});
return EXIT_SUCCESS;
}
修改强>
如果您的类型O
在3方lib中
您可以添加模板来执行此操作。
#include <iostream>
using namespace std;
struct X {};
struct O {
O(X) {
;
}
O() = default;
O(O const&) = default;
O(O&&) = default;
};
struct S {
void f(const X) const {
cout << "X" << endl;
}
void f(O) {
cout << "O" << endl;
}
};
#include <cstdlib>
template<typename TA, typename TB>
void myCall(TA a, TB b) {
((const TA &&)a).f(b);
}
template<>
void myCall(S a, O b) {
a.f(b);
}
template<>
void myCall(S a, X b) {
((const S)a).f(b);
}
int main() {
S s;
myCall(s, X());
//s.f(X());
return EXIT_SUCCESS;
}