Является ли временный объект изначально постоянным? - PullRequest
0 голосов
/ 23 января 2019

Это код UB?

struct A
{
 void nonconst() {}
};

const A& a = A{};
const_cast<A&>(a).nonconst();

Другими словами, является ли (временный) объект изначально const?Я просмотрел стандарт, но не могу найти ответ, поэтому буду признателен за цитирование соответствующих разделов.

Редактировать: для тех, кто говорит, что A{} не const, тогда вы можете сделать A{}.nonconst()?

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Инициализация ссылки a задается как [dcl.init.ref] / 5 (жирный шрифт):

В противном случае, если выражение инициализатора

  • является значением (но не битовым полем) [...]

тогда значение выражения инициализатора в первом случае и результат преобразования во втором случае называется преобразованным инициализатором. Если преобразованный инициализатор является prvalue, его тип T4 настраивается на тип «cv1 T4» ([conv.qual]) и применяется временное преобразование материализации ([conv.rval]).

Таким образом, это означает, что выражение типа prvalue, которое инициализирует ссылку, A{}, настроено на const A.

Затем [conv.rval] заявляет:

Значение типа T может быть преобразовано в значение типа T. Это преобразование инициализирует временный объект ([class.teilitary]) типа T.

Таким образом, тип временного объекта, привязанного к ссылке, совпадает с типом prvalue: const A.

Итак, код const_cast<A&>(a).nonconst(); - это неопределенное поведение .

0 голосов
/ 23 января 2019

Типом временного является тот тип, с которым вы объявили его.

К сожалению, поскольку 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{}); от компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...