Константа и значение l

Мы не можем написать int& ref = 40, потому что нам нужно lvalue с правой стороны. Но мы можем написать const int& ref = 40. Почему это возможно? 40 вместо rvalue rvalue

Я знаю, что это исключение, но почему?

Ответ 1

Как говорит Страуступ:

Инициализатор для const T & не должно быть lvalue или даже типа Т. В таких случаях:

[1] Во-первых, при необходимости применяется неявное преобразование типа в T.

[2] Затем полученное значение помещается во временную переменную тип T.

[3] Наконец, эта временная переменная используется как значение инициализатор.

Итак, при вводе const int& ref = 40 временная переменная int создается за кулисами, а ref привязан к этой временной переменной.

Ответ 2

В языке есть правило, которое позволяет привязывать ссылку const lvalue к rvalue. Основная причина этого правила заключается в том, что если его нет, тогда вам придется предоставлять разные перегрузки функций, чтобы иметь возможность использовать временные аргументы в качестве аргументов:

class T; // defined somewhere
T f();
void g(T const &x);

Используя это правило, вы можете сделать g(f()) без него, чтобы иметь возможность сделать это, вам придется создать другую перегрузку g, которая принимает значение rvalue (и это время, когда rvalue-ссылки даже не были на языке!)

Ответ 3

Почему это возможно?

40 является буквальным здесь. Константные ссылки могут быть инициализированы литералами и временными данными для продления срока их службы. Это можно сделать с помощью компилятора:

int const& ans = 40;
// transformed:
int __internal_unique_name = 40;
int const& ans = __internal_unique_name;

Другая ситуация - когда у вас есть функция, например:

void f( std::string const& s);

и вы хотите называть его

f( "something");

Эта временная переменная может быть привязана только к константной ссылке.

Ответ 4

Вы можете привязать значение r к константной ссылке. Язык гарантирует, что связанный объект будет проживать до тех пор, пока область действия ссылки не закончится и даже не вызовет правильного деструктора статически. Это, например, используемый в реализации ScopeGuard (http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758?pgno=2), чтобы иметь поведение виртуального деструктора, не платя за вызов виртуального метода.