c++ - 有没有办法在提供左值和右值重载的同时删除重复代码?

标签 c++ overloading code-duplication rvalue lvalue

在学习 C++ 时,我决定编写一个简单的模板化二叉搜索树 (bst),并遇到了以下问题:我希望能够通过传递像 这样的左值来构造 bst >const T &val 和类似 T &&val 的右值。同样,我希望能够插入左值和右值。所以我最终得到了很多我不喜欢的重复代码:

/// copy constructor
explicit inline constexpr binary_search_tree(const T &val)
    : _root{std::make_unique<binary_search_tree_node>(val)} {}

/// move constructor
explicit inline constexpr binary_search_tree(T &&val)
    : _root{std::make_unique<binary_search_tree_node>(std::move(val))} {}

对于构造函数,其中 binary_search_tree_nodebinary_search_tree 的私有(private)成员,然后它还必须提供复制和移动构造函数:

struct binary_search_tree_node {
  T value;
  std::unique_ptr<binary_search_tree_node> left;
  std::unique_ptr<binary_search_tree_node> right;

  // prohibit creation of tree_node without value
  inline constexpr binary_search_tree_node() = delete;

  /// copy constructor
  explicit inline constexpr binary_search_tree_node(const T &val)
      : value{val}, left{nullptr}, right{nullptr} {}

  /// move constructor
  explicit inline constexpr binary_search_tree_node(T &&val)
      : value{std::move(val)}, left{nullptr}, right{nullptr} {}
};

另外:

inline constexpr void insert(const T &v) {
  if (!_root) {
    _root = std::make_unique<binary_search_tree_node>(v);
    ++_size;
  } else {
    insert(_root, v);
  }
}

inline constexpr void insert(T &&v) {
  if (!_root) {
    _root = std::make_unique<binary_search_tree_node>(std::move(v));
    ++_size;
  } else {
    insert(_root, std::move(v));
  }
}

用于插入功能。

当我想要搜索一个值时,这个列表还在继续:我是否应该为 find(const T &val) find(T &&val)< 提供重载..?

So my question is whether there is a way of combining these overloads or any other way to remove this duplicate code?

我读到了reference collapsing rules但我不确定我是否可以在这里利用这个概念。

任何其他想法或建议也表示赞赏。

最佳答案

是的,您可以使用引用折叠来减少编写的函数量。

例如,您的函数插入可以使用右值引用+立即上下文来利用引用折叠,从而产生转发引用:

template<typename U>
inline constexpr void insert(U &&v) { // v is a forwarding reference
    if (!_root) {
        // we use std::forward to keep rvalue-ness
        // of the named object when v is an rvalue, but not when it's a lvalue
        _root = std::make_unique<binary_search_tree_node>(std::forward<U>(v));
        ++_size;
    } else {
        insert(_root, std::forward<U>(v));
    }
}

即使参数使用右值引用,由于引用崩溃,左值也将在这里工作。如果 U 推导为 int&,则该参数是 int& && 类型,它会折叠为 int&。相反,如果发送右值,则会将 int 推导为 U,因此参数为 int &&

这种模式称为转发引用。

如您所见,只有当转发参数存在模板参数推导时,此类代码才具有该属性。

请注意,如果没有正确约束,将其设为模板将使其接受比预期更多的类型。

您还可以使用拷贝然后移动以避免代码重复:

inline constexpr void insert(const T &v) {
    T copy = v;
    insert(std::move(copy)); // calls the rvalue overload
}

关于c++ - 有没有办法在提供左值和右值重载的同时删除重复代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60288434/

相关文章:

c++ - 为指向两个不同类的指针重载赋值运算符

Android:相同布局/相似功能的一个或两个 Activity

php - 在网站上查找 C++ 应用程序的最新发布链接

c++ - C++ 参数列表中实例化对象的内存管理

iphone - 如何从类别中的重载函数调用原始函数?

java - Groovy 方法重载 : selection of method prefers interfaces over subclasses?

c++ - 避免在一对几乎相同的基 > 派生类中重复代码

ios - 应用版本重复

c++ - 类声明中缺少分号

c++ - 使用 enable_if 单独定义和声明模板成员函数,其模板参数还包括一个 constexpr 成员函数