防止参数包扩展中的数组衰减 [英] prevent array decay in parameter pack expansion

查看:155
本文介绍了防止参数包扩展中的数组衰减的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以防止从参数包扩展的参数中的数组到指针衰减?

Is it possible to prevent array-to-pointer decay in arguments expanded from a parameter pack?

例如:

#include <iostream>

void foo() {
  std::cout << "empty\n";
}

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

正如你所看到的,第一个调用进入基于数组的重载,但是后续的调用都是基于指针的重载。 有什么方法可以让所有调用去进行基于数组的重载?

As you can see, the first call goes to the array-based overload, but subsequent calls go to the pointer-based overload. Is there any way to get all of the calls to go to the array-based overload?

相关:专业化可变模板函数

推荐答案

要通过参数值传递参数包:

You want to pass the parameter pack by rvalue reference:

void foo(char (&first)[N], Rest&&... rest)
                               ^^

看起来像这样:

#include <iostream>

void foo() {
  std::cout << "empty\n";
}

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

我没有改变其他重载来做同样的事情,但你通常希望他们使用右值引用

I haven't changed the other overloads to do the same, but you'd normally want them to use an rvalue reference as well (if they were actually being used).

编辑:至于为什么你想这么做/为什么它工作:一个右值引用可以绑定到右值或左值。这里我们关心的关键点是,当它绑定到一个左值,它仍然是一个左值。在数组的情况下,它保留其作为数组的身份,所以接收的是数组。

As to why you'd want to do this/why it works: an rvalue reference can bind to either an rvalue or an lvalue. The crucial point we care about here is that when it binds to an lvalue, it remains an lvalue. In the case of an array, it retains its identity as an array, so what's received is an array.

当/如果我们通过值传递数组,

When/if we pass an array by value, it undergoes the normal "decay" to a pointer, just like with a normal function.

对于这种特殊情况,我们也可以使用正常的左值引用 - 但是如果我们这样做,这将工作的任何类型,不是一个左值。例如,如果我们试图调用 foo(1,2,3); ,我们会得到一个错误,因为一个左值引用不能绑定到 1 2 3 。为了处理我们可以传递 const lvalue引用,但是我们不会直接绑定引用到右值 - 我们' d创建一个临时文件,其中包含所传递的右值的副本,然后将左值引用绑定到该临时副本。对于int的特定情况,这可能不是一个主要问题,但使用更复杂(或如果我们想要访问原始,而不是副本)的东西可能是一个问题。

For this specific case, we could also use a normal lvalue reference -- but if we did, that would not work for any type that wasn't an lvalue. For example, if we tried to call foo(1,2,3);, we'd get an error because an lvalue reference can't bind to 1, 2 or 3. To deal with that we could pass a const lvalue reference, but then we wouldn't be binding the reference directly to the rvalue -- we'd be creating a temporary containing a copy of the rvalue that was passed, and then binding the lvalue reference to that temporary copy instead. For the specific case of an int, that probably wouldn't be a major problem, but with something that was more expensive to copy (or if we wanted access to the original, not a copy) that could be a problem.

这篇关于防止参数包扩展中的数组衰减的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆