c++ - 为什么转发引用不是常量?

标签 c++ c++11 forwarding-reference

转发引用应该将参数转发给另一个函数,对吧?那为什么它不是 const 呢?

template <typename T>
void func(const T&&);

非常量引用允许函数修改其参数(而不是仅仅转发它们)。

最佳答案

Why isn't forwarding reference const?

因为希望能够移动一个完美转发的 xvalue。通常不能从 const 引用移动对象,因为移动构造函数的参数需要是非常量。

此外,希望能够将左值绑定(bind)到转发引用中。不可能将左值绑定(bind)到 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 和情况 3 中将 bararg 移动到 fooarg 中,并且我们希望在情况 1 中复制它。转发引用实现了这一点。 const 右值引用不会,因为不可能将 const 引用传递给移动构造函数。


Const 右值引用很少有用。标准库在 few places 中使用它们:

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 防止参数成为转发引用,它会绑定(bind)到任何东西并因此删除任何调用。

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 右值引用用作包装器的返回类型,因此保持包装值的值类别和常量性。


1 标准(草案)说:

[temp.deduct.call] ... 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.

关于c++ - 为什么转发引用不是常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56694942/

相关文章:

c++ - 使用 QObject 属性的指针

c++ - 为什么STL Set会覆盖具有相同值的对

c++ - 为什么我可以在 decltype() 中使用私有(private)默认构造函数?

c++ - 为什么仅当 vector 中已有元素时才调用移动构造函数?

c++ - 对非模板类型使用通用引用?

c++ - 为什么添加 `const` 会使通用引用成为右值

c++ - 如何获取堆栈跟踪信息?

c++ - 如何从 C++ 中的二进制文件中读取类

c++ - 散列 std::vector 独立于项目顺序

c++ - 完美转发 setter 的正确 `enable_if` 约束是什么?