Литеральная инициализация для ссылок на const

Как работает следующий код на С++? Это логично?

const int &ref = 9;
const int &another_ref = ref + 6;

Почему С++ допускает литеральную инициализацию для ссылок const, когда то же самое не допускается для ссылок, не содержащих константы? Например:.

const int days_of_week = 7;
int &dof = days_of_week; //error: non const reference to a const object

Это можно объяснить тем, что для изменения значения переменной, к которой она обращается, может использоваться ссылка не const. Следовательно, С++ не допускает неконстантную ссылку на константную переменную.

Может ли это быть возможным объяснением? С++ не позволяет:

int &ref = 7;

Потому что это не логично, но:

const int &ref = 7;

Почти эквивалентен:

const int val = 7;

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

P.S.: В настоящее время я изучаю Lippman С++ Primer.

Ответ 1

Итак, вы можете написать такой код:

void f( const string & s ) {
}

f( "foobar" );

Хотя, строго говоря, то, что на самом деле происходит здесь, не является литеральным, связанным с ссылкой на const, - вместо этого создается строковый объект:

string( "foobar" );

и эта безымянная строка привязана к ссылке.

Обратите внимание, что на самом деле довольно необычно создавать непараметрические ссылочные переменные, как вы это делаете - основная цель ссылок - служить параметрами функции и возвращаемыми значениями.

Ответ 2

Константные ссылки могут быть инициализированы литералами и временными, поскольку вы можете тривиально преобразовать их в явные переменные:

int const& ans = 42;
// tranformed:
int __internal_unique_name = 42;
int const& ans = __internal_unique_name;

Или, когда время жизни не расширено, например, параметр функции:

f("foobar");
// transformed:
{
  string __internal_unique_name = "foobar";
  f(__internal_unique_name);
}

(Обратите внимание на явный блок в этом случае.)

Хотя возможно сделать что-то подобное в непостоянном случае, что просто не разрешено в currenct С++. С++ 0x (следующий стандарт), однако, будет иметь ссылки r-значения.


Если неясно, ref + 6 из вашего кода создает временный объект, который вы можете визуализировать как:

int const& ref = int(9);
int const& another_ref = int(ref + 6);

// transformed:
int __A = 9;
int const& ref = __A;
int __B = ref + 6;
int const& another_ref = __B;

Это может помочь вам понять/визуализировать происходящее, но вы не должны писать настоящий код, как это. Кроме того, я использовал двойные подчеркивания, чтобы проиллюстрировать эти имена как детали реализации (используемые компилятором) и не должны использоваться вами. Любое имя, содержащее смежные подчеркивания, зарезервировано для реализации С++.

Ответ 3

Ваш код сводится к стандартному правилу С++, где время жизни временного значения привязано к времени жизни ссылки const, которой она назначена. См. GoTW статья GotW # 88: Кандидат на "Most important const" для получения дополнительной информации.

Например, реализация ScopeGuard, описанная Alexandrescu и Marginean в статье доктора Доббса "Generic: измените способ записи исключений Code - Forever "зависит от этого поведения.