Martin Fehrs Asked: 2024-10-02 19:24:31 +0800 CST2024-10-02 19:24:31 +0800 CST 2024-10-02 19:24:31 +0800 CST 完美转发和非类型模板参数 772 “arg” 是通用/转发引用还是右值引用? template<auto&& arg> struct test {}; c++ 3 个回答 Voted Best Answer HolyBlackCat 2024-10-02T19:28:23+08:002024-10-02T19:28:23+08:00 它是一个转发(又称通用)引用。 检查起来很简单: // (This needs to be at namespace scope, addresses local variables can't // be passed to reference or pointer template arguments.). int x; test<x> t; x尽管它是一个左值,但它仍可以编译。 正如@user12002570 所指出的,该标准显然对“转发引用”有一个非常狭窄的定义,仅适用于函数参数,这意味着从技术上讲这不是一个(@Brian Bi 的回答对此进行了更详细的讨论)。但我认为措辞的选择有点缺陷,这不是人们通常使用的定义。 通常人们说“转发引用”来表示一个看似右值引用如果给定一个左值就可以变成左值引用,在这种情况下答案是肯定的。 Brian Bi 2024-10-03T10:05:29+08:002024-10-03T10:05:29+08:00 转发引用仅用于[temp.deduct.call]的目的。 转发引用是对 cv 非限定模板参数的右值引用,该参数不代表类模板的模板参数(在类模板参数推导期间([over.match.class.deduct]))。如果P是转发引用并且参数是左值,则使用类型“左值引用A”代替A类型推导。 在 中template <auto&& arg> struct test {};,引用arg不是转发引用。但是,当为 提供模板参数时arg,[temp.arg.nontype]/1告诉我们发明一个声明 auto&& x = E; 并且 的类型arg是 的类型x。要找到 的类型x,我们必须使用[dcl.type.auto.deduct]/3,然后将其推迟到 [temp.deduct.call] 并使用发明的函数参数类型U&&。这里,P是U&&并且 是转发引用。模板参数U不代表类模板的模板参数;而是U通过“用新发明的类型模板参数替换] [...] [...]”获得的auto,遵循 [dcl.type.auto.deduct]/3 中的措辞。 user12002570 2024-10-02T22:10:49+08:002024-10-02T22:10:49+08:00 “arg” 是通用/转发引用还是右值引用? 如上所述,根据temp.deduct.call ,arg它不是转发引用: 转发引用是对 cv 非限定模板参数的右值引用,该模板参数不代表类模板的模板参数(在类模板参数推导期间([over.match.class.deduct]))。 请注意,粗体强调表明这不是通用/转发参考。 请注意,cppreference 中关于转发引用的文档 与此处的 c++ 标准相矛盾。具体来说,cppreference 页面写道: 转发引用是一种特殊的引用,它保留函数参数的值类别,从而可以通过 std::forward 进行转发。转发引用可以是: 函数模板的函数参数声明为对同一函数模板的 cv-unqualified 类型模板参数的右值引用: auto&&除非从括号括起来的初始化列表中推导出来: auto&& vec = foo(); // foo() may be lvalue or rvalue, vec is a forwarding reference
它是一个转发(又称通用)引用。
检查起来很简单:
x
尽管它是一个左值,但它仍可以编译。正如@user12002570 所指出的,该标准显然对“转发引用”有一个非常狭窄的定义,仅适用于函数参数,这意味着从技术上讲这不是一个(@Brian Bi 的回答对此进行了更详细的讨论)。但我认为措辞的选择有点缺陷,这不是人们通常使用的定义。
通常人们说“转发引用”来表示一个看似右值引用如果给定一个左值就可以变成左值引用,在这种情况下答案是肯定的。
转发引用仅用于[temp.deduct.call]的目的。
在 中
template <auto&& arg> struct test {};
,引用arg
不是转发引用。但是,当为 提供模板参数时arg
,[temp.arg.nontype]/1告诉我们发明一个声明并且 的类型
arg
是 的类型x
。要找到 的类型x
,我们必须使用[dcl.type.auto.deduct]/3,然后将其推迟到 [temp.deduct.call] 并使用发明的函数参数类型U&&
。这里,P
是U&&
并且 是转发引用。模板参数U
不代表类模板的模板参数;而是U
通过“用新发明的类型模板参数替换] [...] [...]”获得的auto
,遵循 [dcl.type.auto.deduct]/3 中的措辞。如上所述,根据temp.deduct.call ,
arg
它不是转发引用:请注意,粗体强调表明这不是通用/转发参考。
请注意,cppreference 中关于转发引用的文档 与此处的 c++ 标准相矛盾。具体来说,cppreference 页面写道: