防止参数包扩展中的数组衰减
prevent array decay in parameter pack expansion
是否可以防止从参数包扩展的参数中数组到指针的衰减?
例如:
#include <iostream>
void foo() {
std::cout << "emptyn";
}
template <typename T, typename... Rest>
void foo(T &&t, Rest... rest) {
std::cout << "T, ...n";
foo(rest...);
}
template <typename... Rest>
void foo(char *p, Rest... rest) {
std::cout << "char*, ...n";
foo(rest...);
}
template <int N, typename... Rest>
void foo(char (&first)[N], Rest... rest) {
std::cout << "char[], ...n";
foo(rest...);
}
int main() {
char a[2], b[2], c[2];
foo(a, b, c);
}
输出:
char[], ...
char*, ...
char*, ...
empty
正如您所看到的,第一个调用转到基于数组的重载,但随后的调用转到基于指针的重载有没有办法让所有调用都转到基于数组的重载
相关:专业化可变模板函数的问题
您想要通过右值引用传递参数包:
void foo(char (&first)[N], Rest&&... rest)
^^
尽管它与手头的问题并不完全相关,但当您提出论点时,您也希望使用std::forward
。因此,经过这些修改,代码总体上看起来是这样的:
#include <iostream>
void foo()
{
std::cout << "emptyn";
}
template <typename T, typename... Rest>
void foo(T&& t, Rest... rest)
{
std::cout << "T, ...n";
foo(std::forward<Rest>(rest)...);
}
template <typename... Rest>
void foo(char const* p, Rest... rest)
{
std::cout << "char*, ...n";
foo(std::forward<Rest>(rest)...);
}
template <int N, typename... Rest>
void foo(char (&first)[N], Rest&&... rest)
{
std::cout << "char[], ...n";
foo(std::forward<Rest>(rest)...);
}
int main()
{
char a[2], b[2], c[2];
foo(a, b, c);
}
给出结果:
char[], ...
char[], ...
char[], ...
empty
我没有改变其他重载来做同样的事情,但你通常希望它们也使用右值引用(如果它们真的在使用的话)。
至于为什么要这样做/为什么它有效:右值引用模板参数可以绑定到右值或左值。我们在这里关心的关键点是,当它与左值绑定时,它仍然是左值。在数组的情况下,它保留其作为数组的身份,因此接收到的是数组。
当/如果我们按值传递数组时,它会经历正常的"0";衰变;指向指针,就像使用普通函数一样。
对于这个特定的情况,我们也可以使用一个正常的左值引用——但如果我们这样做了,将不适用于任何不是左值的类型。例如,如果我们试图调用foo(1,2,3);
,就会出现错误,因为左值引用无法绑定到1
、2
或3
。为了解决这个问题,我们可以传递一个const
左值引用,但我们不会将该引用直接绑定到右值——我们会创建一个包含传递的右值副本的临时副本,然后将左值引用绑定到该临时副本。对于int的特定情况,这可能不是一个大问题,但对于复制成本更高的东西(或者如果我们想要访问原始文件,而不是副本),这可能是一个问题。
@JerryCoffin的回答已经切中要害,但我想补充一句话。您可以将列表处理代码从项目中分离出来,如下所示:
void foo_list() {
std::cout << "emptyn";
}
template <typename T, typename... Rest>
void foo_list(T &&t, Rest&&... rest) {
foo(t);
foo_list(rest...);
}
template <int N>
void foo(char (&t)[N]){
// ...
}
void foo(char *){
// ...
}
// etc...
(也许已经有一个成语了?)。
- 为什么多维数组中的空字符串文本衰减为空指针?
- 从原始指针(衰减的 C 样式数组)和大小生成范围::视图
- 数组变量衰减为指针
- 如果我只有指向第一个数组元素的指针,考虑到数组衰减,是否可以找到数组的长度?
- 在分配给指针到固定数组期间没有指针衰减
- 防止参数包扩展中的数组衰减
- 数组衰减为指针和重载分辨率
- 运行时大小的数组和指针衰减
- 编译器在数组到指针衰减存储中生成的指针在哪里
- C 与 C++ 中的数组衰减规则
- 有没有办法避免数组到指针衰减
- 为什么数组类型不会衰减到类模板的指针
- 我能逆转数组到指针衰减的过程吗?
- C++数组衰减不会发生以供参考,为什么?
- 数组到指针衰减问题
- 为什么在模板函数中数组衰减为指针?
- 数组衰减为Lambda指针
- 如果通过模板函数中的 const 引用传递,数组不会衰减到指针
- 1D 数组衰减为指针,但 2D 数组不会这样做,为什么?
- 将数组显式衰减为指针