Учитывая этот пример:
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, объектом или < strong> ссылка инициализируется из этого элемента (путем инициализации копирования для инициализации списка копирования или путем прямой инициализации для инициализации прямого списка); если для преобразования элемента в T требуется сужающее преобразование (см. ниже), программа имеет неправильный формат.
В противном случае, если T является ссылочным типом, создается prvalue типа, на который ссылается T. prvalue инициализирует свой объект результата путем инициализации списка-копирования или инициализации прямого списка, в зависимости от типа инициализации для справки. Затем prvalue используется для прямой инициализации ссылки. [Примечание: Как обычно, привязка завершится неудачно, и программа будет иметь неправильный формат, если ссылочный тип является ссылкой lvalue на неконстантный тип. - конец примечания]
Для заданных типов «cv1 T1» и «cv2 T2», «cv1 T1» относится к «cv2 T2» по ссылке, если T1 имеет тот же тип, что и T2, или T1 является базовым классом T2. «Cv1 T1» совместим по ссылке с «cv2 T2», если
- T1 связан со ссылкой с T2, или
- T2 - это «функция без исключений», а T1 - «функция», где типы функций в противном случае такой же,
... и позже есть некоторый (лично неоднозначный) язык на определяемых пользователем конверсии:
Например:
Если ссылка представляет собой ссылку lvalue и выражение инициализатора
...
имеет тип класса (т. Е. T2 является типом класса), где T1 не связан со ссылкой на T2 и может быть преобразован в lvalue типа «cv3 T3», где «cv1 T1» совместим по ссылке с «cv3 T3» (это преобразование выбирается путем перечисления применимых функций преобразования ([over.match.ref]) и выбор лучшего из них с помощью разрешения перегрузки),
...
тогда ссылка привязывается к результату преобразования ... value
...
В противном случае, если выражение инициализатора
...
имеет тип класса (т. Е. T2 является типом класса), где T1 не связан со ссылкой на T2, и может быть преобразован в rvalue или функцию lvalue из введите «cv3 T3», где «cv1 T1» совместим по ссылке с «cv3 T3»
... тогда значение ... результата преобразования во втором случае называется преобразованным инициализатором. Если преобразованный инициализатор является prvalue, его тип T4 настраивается на тип «cv1 T4».
...
В противном случае:
- Если T1 или T2 является типом класса и T1 не связан со ссылкой на T2, определяемые пользователем преобразования рассматриваются с использованием правил для инициализации копирования объекта типа «cv1 T1» определяемое пользователем преобразование ... Результат вызова функции преобразования, как описано для инициализации копии без ссылки, затем используется для прямой инициализации ссылки. Для этой прямой инициализации определенные пользователем преобразования не учитываются.
...
В противном случае выражение инициализатора неявно преобразуется в значение типа «cv1 T1». Применяется временное преобразование материализации, и ссылка привязывается к результату.
Эти правила содержат множество нюансов, и я не могу полностью понять каждую ситуацию. Мне кажется, что должно генерироваться prvalue (я согласен с clang), но язык инициализации ссылок и взаимодействия с инициализацией списка очень нечеткий.