Неконстантный конструктор копирования и неявные преобразования возвращаемого значения - PullRequest
7 голосов
/ 19 июня 2011

Рассмотрим следующий код C ++:

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

A f()
{
        // return A(1); // compiles fine
        return 1; // doesn't compile
}

Это прекрасно компилируется на MSVC ++ 2010 (на самом деле на MSVC это работает, даже если я вообще удаляю B) Это не на GCC 4.6.0:

conv.cpp: In function ‘A f()’:
conv.cpp:13:9: error: no matching function for call to ‘A::A(A)’
conv.cpp:13:9: note: candidates are:
conv.cpp:6:2: note: A::A(B)
conv.cpp:6:2: note:   no known conversion for argument 1 from ‘A’ to ‘B’
conv.cpp:5:2: note: A::A(A&)
conv.cpp:5:2: note:   no known conversion for argument 1 from ‘A’ to ‘A&’
conv.cpp:4:2: note: A::A(int)
conv.cpp:4:2: note:   no known conversion for argument 1 from ‘A’ to ‘int’

Что меня смущает, так это сообщение no known conversion for argument 1 from ‘A’ to ‘B’. Как это может быть правдой, учитывая, что A::operator B() очень хорошо определено?

Ответы [ 4 ]

5 голосов
/ 19 июня 2011

Потому что вы не можете сделать более одного неявного преобразования. Вам нужно было бы пойти A::A(A::A(int)::operator B()), чтобы заставить это работать, и это слишком много шагов, чтобы компилятор мог самостоятельно разобраться.

5 голосов
/ 19 июня 2011

Я не думаю, что причиной является «слишком много шагов для самостоятельной оценки», как указывал DeadMG. У меня были конструкции с 3-4 преобразованиями, и компилятор всегда отлично их понимал.

Я полагаю, что проблема скорее в том, что компилятору не разрешено преобразовывать ссылку const в ссылку, отличную от const, от своего имени (это разрешается делать только в том случае, если вы явно указали это с помощью преобразования. ).
А поскольку ссылка на временный объект, который передается в конструктор копирования, является const, а конструктор копирования - нет, она не находит подходящей функции.

РЕДАКТИРОВАТЬ: Я не нашел никакого "реального" кода (см. Комментарии ниже), но построил пример мультизигзагообразного преобразования, который фактически компилируется без ошибок в gcc 4.5. Обратите внимание, что это прекрасно скомпилируется и с -Wall -Wextra, что меня откровенно удивляет.

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;
}
4 голосов
/ 19 июня 2011

Ошибка вполне ясна в списке кандидатов, которые были отклонены. Проблема состоит в том, что неявные последовательности преобразования, включающие пользовательское преобразование на языке C ++, ограничены одним пользовательским преобразованием:

§13.3.3.1.2 [over.ics.user] / 1 Пользовательская последовательность преобразования состоит из начальной стандартной последовательности преобразования, за которой следует пользовательское преобразование (12.3), за которым следует вторая стандартная последовательность преобразования.

Стандартные последовательности преобразования определены в §4 [conv]:

[...] Стандартная последовательность преобразований - это последовательность стандартных преобразований в следующем порядке

  • Ноль или одно преобразование из следующего набора: преобразование lvalue-в-значение, преобразование массива в указатель и преобразование функции в указатель.

  • Ноль или одно преобразование из следующего набора: интегральные преобразования, повышение с плавающей запятой, интегральные преобразования, преобразования с плавающей запятой, преобразования с плавающей запятой, преобразования указателя, преобразования указателя в член и логические преобразования.

  • Ноль или одна квалификация.

Проблема в том, что ваш код не может получить из точки а) int значение r в точку б) B, применяя определенное пользователем преобразование.

В частности, все доступные последовательности преобразования начинаются с определенного пользователем преобразования (неявный конструктор A(int)), который дает значение A r. Оттуда значение r не может быть привязано к неконстантной ссылке на вызов A::A( A& ), поэтому путь отбрасывается. Все остальные пути требуют второго определенного пользователем преобразования, которое не разрешено, и фактически единственный другой путь, который приведет нас к пункту b), требует двух других определенных пользователем преобразований в общей сложности 3.

0 голосов
/ 19 июня 2011

В этой ошибке перечислены все потенциальные кандидаты , которые будут использоваться , и причины, по которым они не могут быть использованы. Он перечисляет преобразование из B, потому что это один из конструкторов, но он не знает, как его использовать в этом случае, поэтому он не знает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...