什么语言规则规定模板化数组中的“T&&”函数参数*不是*转发引用?
What language rules governs that `T&&` in a templated array-by-&& function argument is *not* a forwarding reference?
我正在使用的静态分析工具提示我需要 std::forward
调用链中以下函数的参数:
template<typename T, std::size_t size>
constexpr void f(T (&& arr)[size]) { /* linter: use std::forward on 'arr' here */ }
因为它将函数参数类型标识为转发引用。
然而,对几个编译器的简单测试表明,这不是转发引用。下面的例子
void g() {
int a[3]{1, 2, 3};
f(a); // #1
}
在 #1
(DEMO) 处被拒绝,明确指出函数参数是右值引用:
error: cannot bind rvalue reference of type 'int (&&)[3]' to lvalue of type 'int [3]'
问题
- 上面
f
中的模板化数组 &&
函数参数中的 T&&
不是转发引用是什么语言规则?
相关部分是[temp.deduct.call]/1[强调我的]:
Template argument deduction is done by comparing each function
template parameter type (call it P
) that contains
template-parameters that participate in template argument deduction
with the type of the corresponding argument of the call (call it A
)
as described below. If removing references and cv-qualifiers from
P
gives std::initializer_list<P′>
or P′[N]
for some P′
and N
and the argument is a non-empty initializer list
([dcl.init.list]), then deduction is performed instead for each
element of the initializer list independently, taking P′
as
separate function template parameter types P′i
and the i
:th
initializer element as the corresponding argument. [...]
意思是 [temp.deduct.call]/3 不适用于最初是数组引用类型的 P
(一旦它达到 /3,/3 适用于每个元素)。
但是,如果我们 return 到上面的部分,我们可能会注意到它带有限制
[...] and the argument is a non-empty initializer list [...]
意味着调用,对于 OP 的示例函数 f
,如
f({1, 2, 3}); // [temp.deduct.call]/1 applies
但是参数不是初始化列表而是数组的情况呢?
int arr[3]{1, 2, 3};
f(arr);
[temp.deduct.call]/2 have special rules for arrays, but it does not apply as P
is a reference type, meaning we do end up at [temp.deduct.call]/3:
If P is a cv-qualified type, the top-level cv-qualifiers of P's type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction.
A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])). If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.
但是,f
中的函数参数是对 T[size]
的右值引用,它不是模板参数。这适用于参数不是初始化列表的情况(并且可以说也是这种情况)。
我正在使用的静态分析工具提示我需要 std::forward
调用链中以下函数的参数:
template<typename T, std::size_t size>
constexpr void f(T (&& arr)[size]) { /* linter: use std::forward on 'arr' here */ }
因为它将函数参数类型标识为转发引用。
然而,对几个编译器的简单测试表明,这不是转发引用。下面的例子
void g() {
int a[3]{1, 2, 3};
f(a); // #1
}
在 #1
(DEMO) 处被拒绝,明确指出函数参数是右值引用:
error: cannot bind rvalue reference of type 'int (&&)[3]' to lvalue of type 'int [3]'
问题
- 上面
f
中的模板化数组&&
函数参数中的T&&
不是转发引用是什么语言规则?
相关部分是[temp.deduct.call]/1[强调我的]:
Template argument deduction is done by comparing each function template parameter type (call it
P
) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call itA
) as described below. If removing references and cv-qualifiers fromP
givesstd::initializer_list<P′>
orP′[N]
for someP′
andN
and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list independently, takingP′
as separate function template parameter typesP′i
and thei
:th initializer element as the corresponding argument. [...]
意思是 [temp.deduct.call]/3 不适用于最初是数组引用类型的 P
(一旦它达到 /3,/3 适用于每个元素)。
但是,如果我们 return 到上面的部分,我们可能会注意到它带有限制
[...] and the argument is a non-empty initializer list [...]
意味着调用,对于 OP 的示例函数 f
,如
f({1, 2, 3}); // [temp.deduct.call]/1 applies
但是参数不是初始化列表而是数组的情况呢?
int arr[3]{1, 2, 3};
f(arr);
[temp.deduct.call]/2 have special rules for arrays, but it does not apply as P
is a reference type, meaning we do end up at [temp.deduct.call]/3:
If P is a cv-qualified type, the top-level cv-qualifiers of P's type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction.
A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])). If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.
但是,f
中的函数参数是对 T[size]
的右值引用,它不是模板参数。这适用于参数不是初始化列表的情况(并且可以说也是这种情况)。