使用了构造函数而不是或类型转换运算符

Constructor used instead of or typecast operator

本文关键字:类型转换 运算符 构造函数      更新时间:2023-10-16

我得到了以下代码

    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()运算符可以很容易地解决这个问题,但我想要的是一个解释,而不是解决方案。

A可以由intconst A&构造,B可以转换为这两者,因此这些表达式是令人震惊的,因为编译器无法知道从B创建某些A的两个不同路径是否会导致相同的结果。

这是由于static_cast确定可能的转换路径的方法:

如果new_type类型的临时对象可以用表达式声明和初始化,如new_type Temp(expression);,这可能涉及隐式转换、对new_type构造函数的调用或对用户定义的转换运算符的调用,则static_cast<type>(expression)计算并返回该临时对象的值。(参考)

注意此部分:

可能涉及隐式转换、对new_type构造函数的调用或对用户定义的转换运算符的调用

可以将B隐式转换为int,然后从int构造A

或者您可以根据转换运算符将B转换为A

这就是在这里使用C样式或static_cast时产生歧义的原因。

我建议将构造函数(A(int))设为explicit,而不是运算符。这通常是被通缉的行为。这将导致static_cast<A>(b)的无野心行为:使用operator A()

注意,A a = b;是明确的:它将使用operator A(),因为隐式转换更喜欢用户定义的转换(ref)