11 Declarators [dcl.decl]

11.6 Initializers [dcl.init]

11.6.3 References [dcl.init.ref]

Переменная с объявленным типом “reference to type T должна быть инициализирована. [Example:

int g(int) noexcept;
void f() {
  int i;
  int& r = i;                   // r refers to i
  r = 1;                        // the value of i becomes 1
  int* p = &r;                  // p points to i
  int& rr = r;                  // rr refers to what r refers to, that is, to i
  int (&rg)(int) = g;           // rg refers to the function g
  rg(i);                        // calls function g
  int a[3];
  int (&ra)[3] = a;             // ra refers to the array a
  ra[1] = i;                    // modifies a[1]
}

end example]

Ссылку нельзя изменить для ссылки на другой объект после инициализации. [ Note: Присвоение ссылке присваивается объекту, на который ссылается ссылка ([expr.ass]). ] и являются инициализациями.end noteArgument passing function value return

Инициализатор может быть опущен для ссылки только в объявлении параметра ([dcl.fct]), в объявлении типа возвращаемого значения функции, в объявлении члена класса в его определении класса ([class.mem]) и там, где extern спецификатор используется явно. [Example:

int& r1;                        // error: initializer missing
extern int& r2;                 // OK

end example]

Для заданных типов «cv1 T1» и «cv2 T2», «cv1 T1» reference-related соответствует «cv2 T2», если T1 является тем же типом T2, что иT1 базовый класс , или является его базовым классом T2. «cv1 T1» reference-compatible С «cv2 T2», если

  • T1 относится к ссылке T2, или

  • T2 - это «noexcept функция» и T1 «функция», где типы функций в остальном одинаковы,

и cv1 одно и то же резюме-квалификация , как, или больше резюме , чем-квалификация, cv2. Во всех случаях, когда связь двух типов, связанная со ссылкой или совместимая со ссылкой, используется для установления действительности привязки ссылки и T1 является базовым классом T2, программа, которая требует такой привязки, плохо сформирована, если T1 является inaccessible или неоднозначной. ([class.member.lookup]) базовый класс T2.

Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:

  • Если ссылка является ссылкой lvalue и выражением инициализатора

    • является lvalue (но не битовым полем), а «cv1 T1» совместим со ссылкой с «cv2 T2», или

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

    тогда ссылка привязывается к выражению инициализатора lvalue в первом случае и к результату lvalue преобразования во втором случае (или, в любом случае, к соответствующему подобъекту базового класса объекта). [ Note: Обычные lvalue-to-rvalue, array-to-pointerи function-to-pointer стандартные преобразования не требуются и поэтому подавляются, когда выполняются такие прямые привязки к lvalue. ]end note

    [Example:

    double d = 2.0;
    double& rd = d;                 // rd refers to d
    const double& rcd = d;          // rcd refers to d
    
    struct A { };
    struct B : A { operator int&(); } b;
    A& ra = b;                      // ra refers to A subobject in b
    const A& rca = b;               // rca refers to A subobject in b
    int& ir = B();                  // ir refers to the result of B​::​operator int&
    

    end example]

  • В противном случае ссылка должна быть ссылкой lvalue на энергонезависимый константный тип (т. Е. cv1 Должна быть const), или ссылка должна быть ссылкой на rvalue. [Example:

    double& rd2 = 2.0;              // error: not an lvalue and reference not const
    int  i = 2;
    double& rd3 = i;                // error: type mismatch and reference not const
    

    end example]

    • Если выражение инициализатора

      • является rvalue (но не битовым полем) или функцией lvalue и «cv1 T1» совместим со ссылкой с «cv2 T2», или

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

      тогда значение выражения инициализатора в первом случае и результат преобразования во втором случае называется преобразованным инициализатором. Если преобразованный инициализатор является prvalue, его тип изменяется T4 на тип «cv1 T4» ([conv.qual]) и temporary materialization conversion применяется. В любом случае ссылка привязана к результирующему значению glvalue (или соответствующему подобъекту базового класса).

      [Example:

      struct A { };
      struct B : A { } b;
      extern B f();
      const A& rca2 = f();                // bound to the A subobject of the B rvalue.
      A&& rra = f();                      // same as above
      struct X {
        operator B();
        operator int&();
      } x;
      const A& r = x;                     // bound to the A subobject of the result of the conversion
      int i2 = 42;
      int&& rri = static_cast<int&&>(i2); // bound directly to i2
      B&& rrb = x;                        // bound directly to the result of operator B
      

      end example]

    • Иначе:

      • Если T1 или T2 является типом класса и T1 не является ссылкой , связанных с T2, определяемые пользователем преобразования рассматриваются с использованием правил для копирования-инициализации объекта типа «cv1 T1» с помощью пользовательского преобразования ([dcl.init], [over.match.copy], [over.match.conv]); программа будет неправильно сформирована, если соответствующая не ссылочная инициализация копии будет неправильно сформирована. Результат вызова функции преобразования, как описано для инициализации копии без ссылки, затем используется для прямой инициализации ссылки. Для этой прямой инициализации определенные пользователем преобразования не рассматриваются.

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

      Если T1 ссылка связана с T2:

      • cv1 должно быть такое же резюме, что и, или более высокое резюме, чем cv2,; а также

      • если ссылка является ссылкой rvalue, выражение инициализатора не должно быть lvalue.

      [Example:

      struct Banana { };
      struct Enigma { operator const Banana(); };
      struct Alaska { operator Banana&(); };
      void enigmatic() {
        typedef const Banana ConstBanana;
        Banana &&banana1 = ConstBanana(); // ill-formed
        Banana &&banana2 = Enigma();      // ill-formed
        Banana &&banana3 = Alaska();      // ill-formed
      }
      
      const double& rcd2 = 2;         // rcd2 refers to temporary with value 2.0
      double&& rrd = 2;               // rrd refers to temporary with value 2.0
      const volatile int cvi = 1;
      const int& r2 = cvi;            // error: cv-qualifier dropped
      struct A { operator volatile int&(); } a;
      const int& r3 = a;              // error: cv-qualifier dropped
                                      // from result of conversion function
      double d2 = 1.0;
      double&& rrd2 = d2;             // error: initializer is lvalue of related type
      struct X { operator int&(); };
      int&& rri2 = X();               // error: result of conversion function is lvalue of related type
      int i3 = 2;
      double&& rrd3 = i3;             // rrd3 refers to temporary with value 2.0
      

      end example]

Во всех случаях, кроме последнего (т. Е. Неявного преобразования выражения инициализатора в базовый тип ссылки), ссылка называется bind directly на выражение инициализатора.

[ Note: [class.temporary] описывает время жизни временных файлов, привязанных к ссылкам. ]end note

Это требует conversion function возврата ссылочного типа.