Является ли временный объект изначально постоянным?
Это код UB?
struct A
{
void nonconst() {}
};
const A& a = A{};
const_cast<A&>(a).nonconst();
Другими словами, является (временным) объектом изначально const
? Я просмотрел стандарт, но не могу найти ответ, поэтому буду признателен за цитирование соответствующих разделов.
Редактировать: для тех, кто говорит A{}
не является const
тогда вы можете сделать A{}.nonconst()
?
2 ответа
Инициализация ссылки a
задается [dcl.init.ref] / 5 (жирный шрифт):
В противном случае, если выражение инициализатора
- является значением (но не битовым полем)[...]
тогда значение выражения инициализатора в первом случае и результат преобразования во втором случае называют преобразованным инициализатором. Если преобразованный инициализатор является prvalue, его тип T4 настраивается на тип "cv1 T4" ([conv.qual]) и применяется временное преобразование материализации ([conv.rval]).
Таким образом, это означает, что выражение типа prvalue, которое инициализирует ссылку, A{}
, настроен на const A
,
Тогда [conv.rval] заявляет:
Prvalue типа T может быть преобразовано в xvalue типа T. Это преобразование инициализирует временный объект ([class.teilitary]) типа T.
Таким образом, тип временного объекта, привязанного к ссылке, совпадает с prvalue
тип: const A
,
Итак, код const_cast<A&>(a).nonconst();
является неопределенным поведением.
Типом временного является тот тип, с которым вы объявили его.
К сожалению, как указывает Oliv в своих ответах, правила инициализации ссылок преобразуют тип так, чтобы он соответствовал ссылочному типу, поэтому в этом случае a
на самом деле относится к const A
, Это в основном делает
using const_A = const A;
const A& a = const_A{};
Потому что вы на самом деле можете создавать постоянные значения, если вы хотите, чтобы набор перегрузки не принимал постоянное значение, которое вам нужно
ret_type function_name(some_type const&&) = delete;
в противном случае, если у вас есть
ret_type function_name(some_type const&)
в перегрузке установите его, тогда константа prvalue будет привязана к этому, если вы только удалили
ret_type function_name(some_type&&)
вместо. Вы можете видеть это, работая с
struct bar{};
void foo(bar const&) { std::cout << "void foo(bar const&)\n"; }
void foo(bar&&) =delete;
using c_bar = const bar;
int main()
{
foo(c_bar{});
}
Вот, void foo(bar const&)
вызывается с c_bar{}
на самом деле const
вместо того, чтобы получить ошибку удаленной функции, если вы использовали foo(bar{});
, Добавление
void foo(bar const&&) = delete;
нужно на самом деле остановить foo(c_bar{});
от компиляции.