Home > Mobile >  Why is the const lost in an expression like `const T&` where T is an rvalue reference?
Why is the const lost in an expression like `const T&` where T is an rvalue reference?

Time:04-11

I'm working on a templated class, and given an incoming type T the template needs to map to a "safe" const reference. (This is essentially to avoid handing the ability to mutate to a wrapped function when it's called; see here for the real code).

The original author wrote something equivalent to this:

template <typename T>
using SafeReference =
    std::conditional_t<std::is_scalar_v<T>, T, const T&>;

The scalar part isn't interesting here, but what's interesting is const T&. This looks right to me, but it's not:

struct Foo{};
using Bar = Foo&&;

// A failing static assert, and a reduced version. It turns out `const Bar&`
// is `Foo&`.
static_assert(std::is_same_v<const Foo&, SafeReference<Bar>>);
static_assert(std::is_same_v<const Foo&, const Bar&>);

I understand that Foo&& becomes Foo& due to the rules for reference collapsing. I also understand that the const is probably "lost" because it tries to make a reference const rather than making the referred-to type const. But I don't even know what to Google in order to confirm that.

Which part of the standard says that the const is "lost" in an expression like const T& for a templated T expanding to an rvalue reference?

CodePudding user response:

Which part of the standard says that the const is "lost" in an expression like const T& for a templated T expanding to an rvalue reference?

From dcl.ref/p6:

If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier ([dcl.type.decltype]) denotes a type TR that is a reference to a type T, an attempt to create the type lvalue reference to cv TR creates the type lvalue reference to T, while an attempt to create the type rvalue reference to cv TR creates the type TR.

The quote probably explains the behavior you're seeing.

  • Related