Non-const copy constructor and implicit conversions on return value

别说谁变了你拦得住时间么 提交于 2019-11-30 09:35:43

The error is quite clear on the list of candidates that were rejected. The problem is that implicit conversion sequences involving a user defined conversion in the C++ language are limited to a single user defined conversion:

§13.3.3.1.2 [over.ics.user]/1 A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion (12.3) followed by a second standard conversion sequence.

The standard conversion sequences are defined in §4[conv]:

[...] A standard conversion sequence is a sequence of standard conversions in the following order

  • Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.

  • Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.

  • Zero or one qualification conversion.

The problem is that your code cannot get from point a) int rvalue to point b) B by applying a single user defined conversion.

In particular, all conversion sequences that are available start with a user defined conversion (implicit constructor A(int)) that yield an A rvalue. From there, the rvalue cannot be bound to a non-const reference to call A::A( A& ), so that path is discarded. All the other paths require a second user defined conversion that is not allowed, and in fact the only other path that would get us to point b) requires two other user defined conversions for a total of 3.

Because you cannot do more than one implicit conversion. You would have to go A::A(A::A(int)::operator B()) to make that work, and that's way too many steps for the compiler to figure out on it's own.

I don't think that "too many steps to figure on its own" as DeadMG pointed out is the reason. I've had constructs with 3-4 conversions, and the compiler always figured them out just fine.

I believe the problem is rather that the compiler is not allowed to convert a const reference to a non-constreference on its own behalf (it is only allowed to do that when you explicitly tell it with a cast).
And since the reference to the temporary object that is passed to the copy constructor is const, but the copy constructor is not, it doesn't find a suitable function.

EDIT: I didn't find any "real" code (see comments below) but constructed a multi-zigzag-convert example that actually compiles without errors under gcc 4.5. Note that this compiles just fine with -Wall -Wextra too, which frankly surprises me.

struct B
{
    signed int v;
    B(unsigned short in) : v(in){}
};

struct C
{
    char v;
    C(int in) : v(in){}
};

struct A
{
    int v;
    A(B const& in) : v(in.v){}
    operator C() { return C(*this); }
};

enum X{ x = 1 };

int main()
{
    C c = A(x);
    return 0;
}

The error lists all the potential candidates to be used, and why they cannot be used. It lists the conversion from B because its one of the constructors, but it doesn't know how to use it in this case, so it doesn't.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!