Why is const gone in the return type?

1
2
3
4
5
6
7
8
template <typename T>
const T&& Test(T&& t) {
  return t;
}
......
int i = 0;
int&& irr = std::move(i);
decltype(Test(irr)) t = i;

Since there is a `const` in the return type of function `Test`, I think the type of the function call expression `Test(irr)` should also contain a `const`. Concretely, I think `decltype(Test(irr))` should have deduced type `const int &`. But there is no `const`; the type of `t` is just `int&`. Why is `const` gone?

PS, I used
std::is_const<std::remove_reference<decltype(Test(irr))>::type>::value
to check that the return type of `Test(irr)` is not a reference to const.

PS2, I'm using C++17.
Last edited on
No idea, but Sandor wrote something about const rvalue references in https://www.sandordargo.com/blog/2021/08/18/const-rvalue-references
T is int&.

Question is, what is const T&& in that case according to the reference collapsing rules?

I find it difficult to find information about this exact case but the standard has the following example:

1
2
3
int i;
typedef int& LRI;
const LRI&& r3 = i; // r3 has the type int& 

See https://eel.is/c++draft/dcl.ref#7 for full example and more details.

So I guess this is consistent with Test(irr) returning int& but I cannot explain why the rules are this way.
Last edited on
A function that returns an rvalue-reference provides access for moving which means that the caller can take the contents of the referred object and move it to a different object.

Why would you want to return a const rvalue-reference?
T is int& and the function's return type is T const&&. Substitution produces the type int& const&&, which is collapsed into int&. (Be careful not to make the incorrect derivation const T&&const int& &&const int&.)

We're observing that cv-qualifiers are ignored when applied to a reference type. This happens even when reference collapsing isn't involved:
1
2
3
4
using T = int&;
int x = 0; 
T const rx = x; // int& const  →  int&
rx++; // okay: the declared type of rx is int& 

The key is that the const applies to the reference itself and not to the type being referred to.

I believe that if R is a reference type, it doesn't make sense to distinguish between R const and R for two main reasons:
1. References are usually indistinguishable from the thing they refer to. (Reference transparency [expr.type]/1).
2. References are not objects ([basic.types.general]) and can never be modified ("reseated") to refer to something else.
Last edited on
@Peter87: Thank you for referring me to the relevant Standard. I think this is because reference has no top-level const, so const qualified to reference does not take effect, thus being dropped. Only const qualified to the actual object (say, typedef const int& LRI;) will be preserved. Thank you again for your reply.
Registered users can post here. Sign in or register to post.