我有以下代码
class A {
private:
int n;
public:
A(int n) : n{n} {}
A(const A & a) : n{a.n} {}
};
class B {
private:
int m;
public:
B(int n) : m{n} {}
operator A() const { return A(m); }
operator int() const { return m; }
};
int main(int, char**)
{
B b{1};
(A)b; // Fails
static_cast<A>(b); // Fails
b.operator A(); // OK
}
失败
call of overloaded ‘A(B&)’ is ambiguous
(gcc,但VC ++和clang似乎以同样的方式处理它)
我认为这三者都是完全相同的。使用B的运算符A()进行转换。显然,这不是正在发生的事情。为什么呢?
通过使int()运算符显式化可以很容易地解决问题,但我解释的不是解决方案。
答案 0 :(得分:4)
A
可以从int
或const A&
构造,B
可以转换为这两者,因此这些表达式是不明确的,因为编译器无法知道是否从A
创建一些B
导致相同结果的两种不同途径。
这是由于static_cast
确定可能的转换路径的方式:
如果可以使用表达式声明和初始化类型为
new_type
的临时对象,如new_type Temp(expression);
,可能涉及隐式转换,则调用new_type
的构造函数或调用对于用户定义的转换运算符,然后static_cast<type>(expression)
计算并返回该临时对象的值。 (ref)
请注意这一部分:
可能涉及隐式转换,对
new_type
的构造函数的调用或对用户定义的转换运算符的调用
您可以将B
隐式转换为int
,然后从A
构建int
。
或者您可以根据转换运算符将B
转换为A
。
这就是在这里使用C风格或static_cast
时产生歧义的地方。
我建议制作构造函数(A(int)
)explicit
,而不是运算符。这通常是想要的行为。这会导致static_cast<A>(b)
的行为不明原因:operator A()
被使用。
请注意,A a = b;
是明确的:它将使用operator A()
,因为隐式转化更喜欢用户定义的转化(ref)