Is temporary object originally const?

The initialization of the reference a is given by [dcl.init.ref]/5 (bold mine):

Otherwise, if the initializer expression

  • is an rvalue (but not a bit-field)[...]

then the value of the initializer expression in the first case and the result of the conversion in the second case is called the converted initializer. If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied.

So it means that the type prvalue expression that initialize the reference, A{}, is adjusted to const A.

Then [conv.rval] states:

A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object ([class.temporary]) of type T.

So the type of the temporary object, bound to the reference is the same as the adjusted prvalue type: const A.

So the code const_cast<A&>(a).nonconst(); is undefined behavior.


The type of a temporary is whatever type you declared it with.

Unfortunately, as Oliv points out in their answer reference initialization rules transform the type to match the reference type so in this case a actually refers to a const A. It is basically doing

using const_A = const A;
const A& a = const_A{};

Because you can actually create constant prvalues if you ever want to stop a overload set from accepting a constant prvalue you need to have

ret_type function_name(some_type const&&) = delete;

otherwise if you have

ret_type function_name(some_type const&)

in the overload set it then the constant prvalue would bind to that if you only deleted

ret_type function_name(some_type&&)

instead. You can see this working with

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{});
}

Here, void foo(bar const&) gets called since c_bar{} is actually const instead of getting a deleted function error if you had used foo(bar{});. Adding

void foo(bar const&&) = delete;

is needed to actually stop foo(c_bar{}); from compiling.