【问题标题】:C++ reference for both LValue and Rvalue without type deduction没有类型推导的 LValue 和 Rvalue 的 C++ 参考
【发布时间】:2015-02-27 22:24:06
【问题描述】:

我正在阅读关于左值/右值引用的好教程。如果我在类型推导时理解正确,T&& 之类的东西可以同时接受左值和右值。

但是有没有办法在没有泛型类的情况下实现这一点?我想避免重复我所有接受左值和右值的方法。当然还要避免按值传递大对象。

【问题讨论】:

  • 为什么不要类型扣除?
  • 因为我不需要它。在我的课堂上没有什么是通用的。
  • 我不认为你所有的方法都需要 l 和 r 值。
  • 必须为这两种情况生成不同的代码。例如,对于右值,您可能想要移动,而对于左值,您想要复制。这可以通过模板来实现。如果您不需要并且想要额外的通用性,您可以约束模板。例如,template<typename T, enable_if_t< is_same_v<decay_t<T>, some_type> >> void my_func(T&&);
  • @user1535111:不,不要……

标签: c++ c++11 reference rvalue-reference lvalue


【解决方案1】:

右值引用主要用于移动构造函数和移动赋值。

对于常规方法,您可以只使用一种引用类型:

  • 对于只读参数(无副本),const引用就足够了。

  • 如果你必须做一个副本,你可以通过价值来接受你的论点并使用std::move

例子:

class Test
{
public:

    void displayString(const std::string& s) const { std::cout << s << m_s; }

    void setString(std::string s) { m_s = std::move(s); }

private:
    std::string m_s;
};

【讨论】:

  • std::move 到底是做什么的?是直接复制m_s里面的参数而不是s吗?
  • std::move 执行转换为右值。 std::string 提供 move-assign,它将窃取来自 s 的资源。
  • 所以目标类(在我的例子中是 glm::vec3)必须支持移动语义才能做到这一点,对吧?
  • 目标类必须提供移动赋值/移动构造函数。
  • 谢谢!!最后一个问题:移动数据的优势是什么?我的意思是,在编译器级别。在我看来,数据只需要复制一次(直接在 m_s 中)而不是两次(首先在 setString 的堆栈上然后在 m_s 中)但这完全是我的想法。是这样的吗?
【解决方案2】:

如果您实现的函数不需要右值语义,那么您可以简单地通过引用或常量引用传递参数。

但是,如果您可以利用右值并且不想重复您的代码,您可以按值传递并移动结果。这应该几乎与代码重复或具有通用引用的实现一样有效且更易于维护。

这个答案显示了技术:Should all/most setter functions in C++11 be written as function templates accepting universal references?

// copy, then move
void set_a(A a_) { a = std::move(a_); }

【讨论】:

  • “这应该几乎一样高效,并且更易于维护。” 这取决于用例。 Herb Sutter argues 对于类似 setter 的函数,pass-by-const-ref 是一个合理的默认值(仍在 C++14 中),可以选择稍后添加 pass-by-rvalue-ref。
  • @dyp 是的,我澄清说我的意思是“比通用引用或代码重复更易于维护”。如果您可以避免它,并且一个简单的 const-ref 就足够了,那么我完全同意您的论点。
  • 我不太明白你所说的“比 [..] 使用通用引用的实现更易于维护”。是什么让这样的解决方案更难维护?
  • @dyp 通用引用的类型检查不那么严格。这有时可能是一个优势,但也可能是一个劣势。复制+移动的实现不那么棘手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
  • 2016-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多