Lvalue/rvalue -nes 通用参考编码

Lvalue/rvalue -nes encoding for universal references

我一直在阅读 Effective Modern C++,以下内容引起了我的注意:

斯科特在第 28 项中写道:

Together, these observations about universal references and lvalue/rvalue encoding mean that for this template

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

the deduced template parameter T will encode whether the argument passed to param was an lvalue or an rvalue. The encoding mechanism is simple. When an lvalue is passed as an argument, T is deduced to be an lvalue reference. When an rvalue is passed, T is deduced to be a non-reference. (Note the asymmetry: lvalues are encoded as lvalue references, but rvalues are encoded as non-references.)

有人可以解释为什么选择这种编码机制吗?

我的意思是,如果我们遵循引用折叠规则,那么使用上述带有右值的模板会产生右值引用。据我所知,如果将其推导为右值引用,一切都会正常工作。为什么它被编码为非参考?

假设您需要传递 param。事实上,您需要将其存储以供终生使用。实际上,您只需使用 T:

template <typename T>
struct store { T val; };

template<typename T> void func(T&& param) {
    store<T> s{std::forward<T>(param)};
}

这是有效的,因为如果 param 被左值传入,T 将是左值引用类型,而我们只是复制引用。如果 param 由右值传入,我们需要取得所有权 - T 是非引用类型,所以我们最终移动构造为 s.

事实上我可以在这里使用 T 作为 store 的模板参数,而不是 std::conditional_t<std::is_lvalue_reference<T>::value, T, std::remove_reference_t<T>> 这可能不是偶然的。

我认为你想错了。与其问"why not always make T a reference type",不如换个角度看:

假设你有 template <typename T> void f(T&&t).

将其称为 int i; f(i);,需要一些 T,以便 T&& 解析为 int&。什么是最简单的 T 可以做到这一点?这是 int&.

将其称为 f(0);,需要一些 T,以便 T&& 解析为 int&&。什么是最简单的 T 可以做到这一点?是 int,不是 int&&

int&&在这里根本没有任何优势。