Search code examples
c++privateradixconversion-operatorcopy-initialization

conversion operator bypasses constructor of the derived type and skips to copy-initialization of the base type?


There is something wrong with how the conversion operator behaves in the following code:

struct A{
    A(){};
    A(const A &) = delete;
};

struct B : A{
    B(const B & x){};
    B(int x){};
};

struct C{
    operator B() {
        return B(1);
    };
};

void foo(const A & x){
};

int main(){
    C c;
    foo(c.operator B()); //1) Ok    
    foo(c); //2) Not Ok
    return 0;
};

I get an error in the call 2):

test.cpp:24:7: error: use of deleted function 'A::A(const A&)'
  foo(c); //2) Not Ok
       ^

So the question is: why in the hell it wants to copy-initialize A? Note, B declares its own copy constructor. I would though that call 1) which succeeds is identical to 2), but apparently it isn't?

On the practical problem I am trying solve: in the class C I wanted to provide a conversion to a third party class A, which prohibits copying. The idea was to return a proxy B : A that would add the move semantics on top of A. Is there perhaps another way to define the conversion operator to get A on the stack while obeying its non-copy policy.


Solution

  • In C++98 when a const reference is initialized with an rvalue, the compiler is allowed to create a temporary copy of the rvalue. For this purpose it might require a copy constructor to be present.

    Even though you are not compiling in C++98 mode, the error message you observe certainly looks like a lingering remnant of that obsolete requirement. In your case a const A & reference is initialized with an rvalue of type B.

    The code seems to compile fine with GCC (http://coliru.stacked-crooked.com/a/0d58fd31a0b50cf5), meaning that what you observe is most likely a bug in your compiler. I'm just suggesting a possible rationale behind that bug.