了解勘误表中有关 EMC++ 第 41 项的评论

Understanding comment from the errata about Item 41 of EMC++

在项目 41 中,Scott Meyers 写了以下两个 类:

class Widget {
public:
  void addName(const std::string& newName)   // take lvalue;
  { names.push_back(newName); }              // copy it

  void addName(std::string&& newName)        // take rvalue;
  { names.push_back(std::move(newName)); }   // move it; ...

private:
  std::vector<std::string> names;
};
class Widget {
public:
  template<typename T>                            // take lvalues
  void addName(T&& newName)                       // and rvalues;
  {                                               // copy lvalues,
    names.push_back(std::forward<T>(newName)); }  // move rvalues;
  }                                               // ...
private:
  std::vector<std::string> names;
};

评论中写的是正确的,即使它根本不意味着这两个解决方案是等价的,并且书中确实讨论了一些差异。

In the errata,然而,作者评论了书中未讨论的另一个区别:

Another behavioral difference between (1) overloading for lvalues and rvalues and (2) a template taking a universal reference (uref) is that the lvalue overload declares its parameter const, while the uref approach doesn't. This means that functions invoked on the lvalue overload's parameter will always be the const versions, while functions invoked on the uref version's parameter will be the const versions only if the argument passed in is const. In other words, non-const lvalue arguments may yield different behavior in the overloading design vis-a-vis the uref design.

但我不确定我是否理解它。

其实写这个问题我大概是明白了,但是我还不是很确定所以不写答案

可能作者是说当一个非const左值被传递给addName时,newName在第一个代码中是const,并且非const 在第二个代码中,这意味着 如果 newName 被传递给另一个函数(或在其上调用了一个成员函数),那么该函数将需要接受 const 参数(或者是 const 成员函数).

我的解释正确吗?

但是,我看不出这在具体示例中有何不同,因为在 newName 上没有调用任何成员函数,也没有将其传递给具有不同的函数const 和非 const 参数的重载 (不完全是:std::vector<T>::push_back 有两个 const T& 参数和 T&& 参数的重载`,但是左值仍将仅绑定到前一个重载...)。

在第二种情况下,当一个const std::string左值传递给模板时

  template<typename T>
  void addName(T&& newName)
  { names.push_back(std::forward<T>(newName)); }

实例化结果如下(我删除了 std::forward 调用,实际上是空操作)

  void addName(const std::string& newName)
  { names.push_back(newName); }

而如果传递了 std::string 左值,则 addName 的结果实例是

  void addName(std::string& newName)
  { names.push_back(newName); }

这意味着const版本的std::vector<>::push_back被称为.

在第一种情况下,当 std::string 左值传递给 addName 时,选择第一个重载 ,而不管 const -ness

  void addName(const std::string& newName)
  { names.push_back(newName); }

这意味着在这两种情况下都选择了 std::vector<>::push_backconst 重载。