使用完美转发的衰减
Using decay with perfect forwarding
假设我们有 2 个函数:
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};
}
我们这样称呼它们:
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&
尽管两个函数的推导相似,但在第二个函数中我必须使用 std::decay_t 来编译应用程序。为什么会这样?
我使用 Visual studio 2019 和 /std:c++17 标志
当你有像
这样的函数时
template <typename T> void callDecayExample1(T& t)
{
std::initializer_list<T> testList2{ 1, 2, 3 };
}
然后 T
只会被推断为非引用类型。如果你给它一个int&
,那么T
就变成了int
,这样t
就变成了int&
。因此,您不需要使用 decay
.
在
template <typename T> void callDecayExample2(T&& t)
{
std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}
如果您传递 int&
,则 T
被推断为 int&
,然后引用折叠规则将 int& &&
转换为 int&
类型t
个。这意味着如果没有 decay
你会尝试做一个你做不到的 std::initializer_list<int&>
。
说推导类型相同是不正确的:
#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;
}
打印:
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&]
在您的情况下,std::decay
删除了第二个示例中存在的额外引用。
因为T
可能是也可能不是引用类型:
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&
假设我们有 2 个函数:
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};
}
我们这样称呼它们:
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&
尽管两个函数的推导相似,但在第二个函数中我必须使用 std::decay_t 来编译应用程序。为什么会这样?
我使用 Visual studio 2019 和 /std:c++17 标志
当你有像
这样的函数时template <typename T> void callDecayExample1(T& t)
{
std::initializer_list<T> testList2{ 1, 2, 3 };
}
然后 T
只会被推断为非引用类型。如果你给它一个int&
,那么T
就变成了int
,这样t
就变成了int&
。因此,您不需要使用 decay
.
在
template <typename T> void callDecayExample2(T&& t)
{
std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}
如果您传递 int&
,则 T
被推断为 int&
,然后引用折叠规则将 int& &&
转换为 int&
类型t
个。这意味着如果没有 decay
你会尝试做一个你做不到的 std::initializer_list<int&>
。
说推导类型相同是不正确的:
#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;
}
打印:
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&]
在您的情况下,std::decay
删除了第二个示例中存在的额外引用。
因为T
可能是也可能不是引用类型:
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&