Является ли временный объект изначально постоянным?

Это код 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{}); от компиляции.

Другие вопросы по тегам