Assume we have 2 functions:
template <typename T> void callDecayExample1(T& t)
{
std::initializer_list<T> testList2{ 1, 2, 3 };
}
template <typename T> void callDecayExample2(T&& t)
{
std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}
and we call them like this:
const int& i = 2;
int j = 10;
int& ref_j = j;
callDecayExample1(i); // deduced as const int&
callDecayExample1(ref_j);// deduced as int&
callDecayExample1(j); // deduced as int&
callDecayExample2(i); // deduced as const int&
callDecayExample2(ref_j);// deduced as int&
callDecayExample2(j); // deduced as int&
depspite the similar deducing in both functions, in the 2nd function I have to use std::decay_t to compile the application. Why it is so?
I use Visual studio 2019 with the /std:c++17 flag
When you have a function like
template <typename T> void callDecayExample1(T& t)
{
std::initializer_list<T> testList2{ 1, 2, 3 };
}
then T
is only going to get deduced as a non reference type. If you give it a int&
, then T
becomes int
so that t
becomes a int&
. Because of that you do not need to use decay
.
In
template <typename T> void callDecayExample2(T&& t)
{
std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}
If you pass a int&
then T
gets deduced as a int&
, and then reference collapsing rules turn int& &&
into int&
for the type of t
. This means that without decay
you would try to make a std::initializer_list<int&>
which you can't do.
It is not correct to say that the deduced types are identical:
#include <iostream>
template <typename T>
void printType()
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
}
template <typename T>
void callDecayExample1(T& t)
{
printType<T>();
std::initializer_list<T> testList2{1, 2, 3};
}
template <typename T>
void callDecayExample2(T&& t)
{
printType<T>();
std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}
int main()
{
const int i = 0;
int j = 1;
int& ref_j = j;
callDecayExample1(i);
callDecayExample1(ref_j);
callDecayExample1(j);
callDecayExample2(i);
callDecayExample2(ref_j);
callDecayExample2(j);
return 0;
}
prints:
void printType() [with T = const int]
void printType() [with T = int]
void printType() [with T = int]
void printType() [with T = const int&]
void printType() [with T = int&]
void printType() [with T = int&]
In your situation std::decay
removes the extra reference that is present in the second example.
Because T
may or may not be a reference type:
template <typename T> void callDecayExample2(T&& t)
{
if constexpr (std::is_same<T, int&>::value)
std::initializer_list<std::decay_t<T>> testList{ 1, 2, 3 };
else
std::initializer_list<T> testList{ 1, 2, 3 };
}
int val = 5;
callDecayExample2(5) // T = int
callDecayExample2(val) // T = int&
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.