Non-const copy constructor and implicit conversions on return value

前端 未结 4 717
长发绾君心
长发绾君心 2020-12-31 23:51

Consider the following C++ code:

struct B { };
struct A
{
        A(int);
        A(A&); // missing const is intentional
        A(B);
        operator B         


        
相关标签:
4条回答
  • 2021-01-01 00:16

    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.

    0 讨论(0)
  • 2021-01-01 00:18

    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;
    }
    
    0 讨论(0)
  • 2021-01-01 00:19

    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.

    0 讨论(0)
  • 2021-01-01 00:21

    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.

    0 讨论(0)
提交回复
热议问题