转发引用应该将参数转发给另一个函数,对吗?那么为什么不是 const 呢?
template <typename T>
void func(const T&&);
非常量引用允许函数修改其参数(而不仅仅是转发它们)。
转发引用应该将参数转发给另一个函数,对吗?那么为什么不是 const 呢?
template <typename T>
void func(const T&&);
非常量引用允许函数修改其参数(而不仅仅是转发它们)。
为什么不转发参考常量?
因为希望能够移动完美转发的 xvalue。通常不能从 const 引用中移动对象,因为移动构造函数的参数需要是非常量的。
此外,希望能够将左值绑定到转发引用中。无法将const T&&
const 右值引用绑定到其中的左值 - 它根本不是转发引用1。
如果您不想离开论点,而只是不断地引用它,那么您不需要转发引用。在这种情况下,一个 const 左值引用就足够了。
例子:
struct S {
S() = default;
S(S&&) = default; // move
S(const S&) = default; // copy
};
void foo(S fooarg);
template <typename T>
void bar(T&& bararg) { // forwarding reference
foo(std::forward<T>(bararg));
}
// call site
S s;
bar(s); // 1 copy
bar(S{}); // 2 move
bar(std::move(s)); // 3 move
在这里,我们希望在案例 2 和 3bararg
中移动fooarg
,并且我们希望在案例 1 中复制它。转发引用实现了这一点。const 右值引用不会,因为不可能将 const 引用传递给移动构造函数。
常量右值引用很少有用。标准库在几个地方使用它们:
template <class T> void as_const(const T&&) = delete;
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
这些删除的重载的目的是防止使用临时参数(右值)调用函数。const
防止参数成为转发引用,这将绑定到任何东西,因此删除任何调用。
constexpr const T&& optional::operator*() const&&;
constexpr const T&& optional::value() const &&;
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
上面, const rvalue 引用在访问包装值时用作包装器的返回类型,因此保持包装值的值类别和常量。
1标准(草案)说:
[temp.deduct.call] ...转发引用是对不代表类模板的模板参数的cv非限定模板参数的右值引用(在类模板参数推导期间([over.match.class.deduct ]))。如果 P 是转发引用并且参数是左值,则使用类型“对 A 的左值引用”代替 A 进行类型推导。