转换运算符绕过派生类型的构造函数并跳到基类型的复制初始化?

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

转换运算符在以下代码中的行为有问题:

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;
};

我在调用 2 时出错):

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

所以问题是:到底为什么要复制初始化 A?注意,B 声明了它自己的复制构造函数。我会认为成功的调用 1) 与 2) 相同,但显然不是?

关于我尝试解决的实际问题:在class C中我想提供一个转换给第三方class A,它禁止复制。这个想法是 return 代理 B : A 将在 A 之上添加移动语义。是否有另一种方法来定义转换运算符以在遵守其非复制策略的同时将 A 放入堆栈。

gcc 6.1.1 编译显示的代码没有任何错误:

$ cat t.C
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;
};
$ g++ -g -std=c++1z -o t t.C
$ g++ --version
g++ (GCC) 6.1.1 20160621 (Red Hat 6.1.1-3)
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我认为显示的代码没有任何问题。我相信这是您使用的任何编译器中的错误。

在 C++98 中,当使用右值初始化 const 引用时,允许编译器创建右值的临时副本。为此,它可能需要存在一个复制构造函数。

即使您没有在 C++98 模式下编译,您观察到的错误消息肯定看起来像是那个过时要求的挥之不去的残余。在您的情况下,const A & 引用是使用 B.

类型的右值初始化的

代码似乎可以用 GCC (http://coliru.stacked-crooked.com/a/0d58fd31a0b50cf5) 编译,这意味着您观察到的很可能是编译器中的错误。我只是提出该错误背后的可能理由。