dfr*_*fri 5 c++ templates language-lawyer forwarding-reference
我正在使用的静态分析工具提示我需要std::forward调用链中以下函数的参数:
template<typename T, std::size_t size>
constexpr void f(T (&& arr)[size]) { /* linter: use std::forward on 'arr' here */ }
Run Code Online (Sandbox Code Playgroud)
因为它将函数参数类型标识为转发引用。
然而,对多个编译器的简单测试表明,这不是转发引用。下面的例子
void g() {
int a[3]{1, 2, 3};
f(a); // #1
}
Run Code Online (Sandbox Code Playgroud)
#1在(DEMO )处被拒绝,明确指出函数参数是右值引用:
Run Code Online (Sandbox Code Playgroud)error: cannot bind rvalue reference of type 'int (&&)[3]' to lvalue of type 'int [3]'
T&&的模板化数组函数&&参数f不是转发引用?相关部分是[temp.deduct.call]/1 [重点是我的]:
\n\n\n模板参数推导是通过将包含参与模板参数推导的模板参数的每个函数模板参数类型(称为
\nP)与调用的相应参数类型(称为A)进行比较来完成的,如下所述。如果从\n 中删除引用和 cv 限定符给出Porstd::initializer_list<P\xe2\x80\xb2>对于P\xe2\x80\xb2[N]某些P\xe2\x80\xb2\nN并且参数是非空初始化器列表\n([dcl.init.list]),则对初始化器的每个\n元素执行推导独立列出,将P\xe2\x80\xb2单独的函数模板参数类型P\xe2\x80\xb2i和i第一个初始化元素作为相应的参数。[...]
含义[temp.deduct.call]/3不适用于P最初是数组引用类型的 a (一旦达到 /3,/3 适用于每个元素)。
但是,如果我们返回到上面的部分,我们可能会注意到它带有限制
\n\n\n[...]并且参数是一个非空的初始值设定项列表[...]
\n
对于 OP 的示例函数来说,意味着一个调用f,例如
f({1, 2, 3}); // [temp.deduct.call]/1 applies\nRun Code Online (Sandbox Code Playgroud)\n但是如果参数不是初始化列表而是数组呢?
\nint arr[3]{1, 2, 3};\nf(arr);\nRun Code Online (Sandbox Code Playgroud)\n[temp.deduct.call]/2对于数组有特殊规则,但它并不像P引用类型一样适用,这意味着我们最终会到达[temp.deduct.call]/3:
\n\n如果 P 是 cv 限定类型,则类型推导时将忽略 P 类型的顶级 cv 限定符。如果 P 是引用类型,则使用 P 引用的类型进行类型推导。
\n转发引用是对 cv 不合格模板参数的右值引用,该模板参数不表示类模板的模板参数(在类模板参数推导 ([over.match.class.deduct]) 期间)。如果 P 是转发引用并且参数是左值,则使用对 A\xe2\x80\x9d 的类型 \xe2\x80\x9clvalue 引用代替 A 进行类型推导。
\n
然而,中的函数参数f是对 的右值引用T[size],它不是模板参数。这控制了参数不是初始值设定项列表时的情况(也可以说是这种情况)。
| 归档时间: |
|
| 查看次数: |
104 次 |
| 最近记录: |