Список инициализации ссылки: правильно ли GCC или Clang? - PullRequest
0 голосов
/ 10 января 2019

Данный пример:

int g_i = 10;
struct S {
    operator int&(){ return g_i; }
};

int main() {
    S s;
    int& iref1 = s; // implicit conversion

    int& iref2 = {s}; // clang++ error, g++ compiles fine:
                      // `s` is converted
                      // to a temporary int and binds with
                      // lvalue reference

    int&& iref3 = {s}; // clang++ compiles, g++ error:
                       // cannot bind rvalue reference
                       // to lvalue
}

Ошибки описаны в комментариях.
gcc 8.2.1 и clang 7.0.1 были использованы и не согласны с тем, что происходит в этом примере. Может ли кто-нибудь уточнить это?

В инициализации списка :

В противном случае , если в списке инициализатора есть один элемент типа E и либо T не является ссылочным типом, либо его ссылочный тип связан со ссылкой на E , объект или ссылка инициализируется из этого элемента (путем инициализации копирования для инициализации списка копирования или путем прямой инициализации для инициализации прямого списка); если для преобразования элемента в T требуется сужающее преобразование (см. ниже), программа является некорректной.

В противном случае, если T является ссылочным типом, генерируется prvalue типа, на который ссылается T. prvalue инициализирует свой результирующий объект путем копирования-инициализации списка или прямой-инициализации списка, в зависимости от вид инициализации для ссылки. Затем значение prvalue используется для прямой инициализации ссылки. [Примечание: Как обычно, привязка завершится неудачно, и программа будет неправильно сформирована, если ссылочный тип является lvalue-ссылкой на неконстантный тип. - конец примечания]

В исходной инициализации :

Для данных типов «cv1 T1» и «cv2 T2», «cv1 T1» относится к «cv2 T2», если T1 относится к тому же типу, что и T2, или T1 является базовым классом для T2 * 1035. *. «Cv1 T1» совместим с «cv2 T2», если
- T1 связан со ссылкой на T2, или
- T2 - это «функция без исключения», а T1 - это «функция», где типы функций в остальном одинаковы,

... и позже есть некоторые (лично неоднозначные) языки для пользовательских преобразований :

Например:

Если ссылка является ссылкой lvalue и выражением инициализатора
...
имеет тип класса (т. Е. T2 является типом класса), где T1 не связан со ссылкой на T2 и может быть преобразован в lvalue типа «cv3 T3», где «cv1 T1» является ссылочно-совместимым с «cv3 T3» (это преобразование выбирается путем перечисления применимых функций преобразования ([over.match.ref]) и выбора наилучшего с помощью разрешения перегрузки),
...
тогда ссылка привязывается к ... значению результата преобразования

...

В противном случае, если выражение инициализатора
...
имеет тип класса (т. е. T2 является типом класса), где T1 не связан со ссылкой на T2 и может быть преобразован в rvalue или функцию lvalue типа «cv3 T3», где «cv1 T1» совместим со ссылками с «cv3 T3»
... тогда значение ... результата преобразования во втором случае называется преобразованным инициализатором. Если преобразованный инициализатор является prvalue, его тип T4 настраивается на тип «cv1 T4»

...

В противном случае:
- Если T1 или T2 является типом класса и T1 не связан со ссылкой на T2, пользовательские преобразования рассматриваются с использованием правил для инициализации копирования объекта типа «cv1 T1» путем пользовательского преобразования ... Результат вызова функции преобразования, как описано для инициализации копирования без ссылки, затем используется для прямой инициализации ссылки. Для этой прямой инициализации пользовательские преобразования не рассматриваются .

...

В противном случае, выражение инициализатора неявно преобразуется в значение типа «cv1 T1» . Применяется временное преобразование материализации, и ссылка привязывается к результату.

Эти правила довольно тонкие, и я не могу полностью понять каждую ситуацию. Мне кажется, что должно генерироваться prvalue (я согласен снг), но язык инициализации ссылок и взаимодействия с инициализацией списка очень размыт.

1 Ответ

0 голосов
/ 10 января 2019

Давайте прочитаем стандарт в правильном порядке, чтобы мы знали, какие разделы применимы к данной ситуации.

[dcl.init] / 17 говорит:

Семантика инициализаторов выглядит следующим образом ... Если инициализатор является (без скобок) braced-init-list или = braced-init-list объект или ссылка инициализируются списком (11.6.4) ...

Итак, мы идем в [dcl.init.list] (11.6.4). Пункт 3 гласит:

Инициализация списка объекта или ссылки типа T определяется следующим образом: (... случаи, которые не применяются, исключаются из этой цитаты ...) В противном случае, если список инициализатора содержит один элемент типа E и либо T не является ссылочным типом, либо его ссылочный тип связан со ссылкой E ... в противном случае, если T является ссылочным типом, значение типа, на которое ссылается T генерируется. Prvalue Инициализирует свой объект результата путем копирования-инициализации-списка или прямой-инициализации списка, в зависимости от вида инициализации для ссылки. Затем значение prvalue используется для прямой инициализации ссылки. [ Примечание: как как правило, привязка завершится неудачно, и программа будет неправильно сформирована, если ссылочный тип является lvalue-ссылкой на неконстантный тип. - Конечная заметка ]

Согласно [dcl.init.ref] / 4:

Данные типы « cv1 T1» и « cv2 T2», « cv1 T1» имеют отношение , относящееся к ссылкам От до cv2 T2, если T1 того же типа, что и T2, или T1 - базовый класс T2.

Следовательно, в вашем коде ссылочный тип int не связан со ссылками на тип в списке инициализатора, а именно S. Таким образом, с помощью [dcl.init.list] / 3 генерируется значение типа int, которое принимает форму int{s}. И, как отмечается в примечании, в случае iref2 программа плохо сформирована, поскольку пытается связать неконстантную ссылку lvalue с prvalue. В случае iref3 программа должна скомпилироваться, поскольку iref3 привязывается к результату prvalue int{s}.

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