Оператор преобразования обходит конструктор производного типа и пропускает инициализацию копирования базового типа?

Что-то не так с поведением оператора преобразования в следующем коде:

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), но, по-видимому, это не так?

По практической проблеме, которую я пытаюсь решить: в классе C я хотел обеспечить преобразование в сторонний класс A, который запрещает копирование. Идея заключалась в том, чтобы вернуть прокси-сервер B: A, который бы добавил семантику перемещения поверх A. Может быть, есть другой способ определить оператор преобразования, чтобы получить A в стеке, соблюдая при этом свою политику не копирования.

3

Решение

В C ++ 98, когда константная ссылка инициализируется значением r, компилятору разрешается создавать временную копию значения r. Для этого может потребоваться наличие конструктора копирования.

Даже если вы не компилируете в режиме C ++ 98, сообщение об ошибке, которое вы наблюдаете, определенно выглядит как пережиток этого устаревшего требования. В вашем случае const A & ссылка инициализируется значением r типа B,

Код, похоже, хорошо компилируется с GCC (http://coliru.stacked-crooked.com/a/0d58fd31a0b50cf5), то есть то, что вы наблюдаете, скорее всего, ошибка в вашем компиляторе. Я просто предлагаю возможное обоснование этой ошибки.

1

Другие решения

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.

Я не вижу ничего плохого в показанном коде. Я считаю, что это ошибка любого компилятора, который вы используете.

0