Nat*_*ohl 9 c++ templates c++11
是否可以防止从参数包扩展的参数中的数组到指针衰减?
例如:
#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);
}
Run Code Online (Sandbox Code Playgroud)
...输出:
char[], ...
char*, ...
char*, ...
empty
Run Code Online (Sandbox Code Playgroud)
如您所见,第一次调用转到基于数组的重载,但后续调用转到基于指针的重载. 有没有办法让所有的调用转到基于数组的重载?
您想通过rvalue引用传递参数包:
void foo(char (&first)[N], Rest&&... rest)
^^
Run Code Online (Sandbox Code Playgroud)
所以代码整体看起来像这样:
#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);
}
Run Code Online (Sandbox Code Playgroud)
给出结果:
char[], ...
char[], ...
char[], ...
empty
Run Code Online (Sandbox Code Playgroud)
我没有改变其他重载来做同样的事情,但你通常也希望它们也使用右值引用(如果实际使用它们).
编辑:至于你为什么要这样做/为什么它起作用:右值引用可以绑定到右值或右值.我们关心的关键点是当它与左值结合时,它仍然是左值.在数组的情况下,它将其身份保留为数组,因此接收的是数组.
当/如果我们按值传递数组时,它会经常正常地"衰减"到指针,就像使用普通函数一样.
对于这个特定的情况下,我们也可以用一个正常的左值参考-但如果我们这样做,会不会对任何类型的,这不是一个左值工作.例如,如果我们试图调用foo(1,2,3);
,我们会收到错误,因为左值引用无法绑定1
,2
或3
.为了解决这个问题,我们可以传递一个const
左值引用,但是我们不会直接将引用绑定到rvalue - 我们将创建一个临时包含传递的rvalue的副本,然后绑定左值引用而是临时副本.对于int的特定情况,这可能不是一个主要问题,但复制成本更高(或者如果我们想要访问原始文件,而不是副本)可能是一个问题.
@JerryCoffin的答案已经到了现场,但我想补充一点.您可以将列表处理代码与第一项分开,如下所示:
void foo_list() {
std::cout << "empty\n";
}
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...
Run Code Online (Sandbox Code Playgroud)
(也许已经有了这个成语?).