Consider the following code:
#include <type_traits>
int main() {
const int& p = 42;
auto v1 = decltype(p){};
static_assert(std::is_same_v<decltype(v1), int>);
decltype(p) v2{};
static_assert(std::is_same_v<decltype(v2), const int&>);
// auto v3 = X(const int&)X {};
}
Type of v1
is deduced as int
. At the same time type of v2
is expectedly deduced as const int&
. I think the first step for v1
could be treated as adding one more type alias using T = decltype(p);
and then auto v4 = T{};
. How this expression (decltype(p){}
or T{}
) is treated by compiler? I know that {}
part is for instantiation, but how the resulting type of v1
is not a reference type?
Yet another question: is there a way to declare v3
variable of the same type as v1
using explicitly noted type const int&
(instead of decltype(p)
)?
Any links to standard would be appreciated.
(To the downvoter(s): if you downvoted because you think quoting Scott Meyers is not equivalent to quoting the standard, oh well...)
As you can read from Effective Modern C++ (augmented with the part of the errata that you can reach by searching for Case 2:
at that link, and that just makes the following read simpler, but it's not essential to the question):
If
ParamType
is a non-reference [...] ifexpr
's type is a reference, ignore the reference part. If [...]expr
isconst
, ingore that too. If it'svolatile
, also ignore that.
where param
is the declaration specifier, which in your case is just auto
, i.e. a non-reference.
In other words, you're creating v1
via plain auto
(not auto&
), i.e. by copy, so it does not matter whether you are initializing it with an entity which is reference or not, or even with const
or not (or volatile
or not, fwiw), because you're copying it.
Think about the simpler case,
int i = 3;
int& p = i;
auto v1 = p;
as far as v1
is concerned, it's really not important whether it is initalized with one (i
) or the other (p
) name by which the same entity is known, because it will get a copy of whatever value that entity has.
auto
type deduction works just like template type deduction (except for a difference in how they deal with braced initializer, which is not relevant in this case), and for both of them you can refer to Scott Meyers' Effective Modern C++.