问题描述
在第 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,然而,作者评论了书中未讨论的另一个差异:
(1) 左值和右值的重载与 (2) 采用通用引用 (uref) 的模板之间的另一个行为差异是左值重载声明了其参数 const
,而 uref 方法则没有。这意味着在左值重载的参数上调用的函数将始终是 const
版本,而在 uref 版本的参数上调用的函数只有在传入的参数为 const
时才会是 const
版本.换句话说,非 const
左值参数可能会在重载设计中产生与 uref 设计不同的行为。
但我不确定我是否理解。
实际上,写这个问题我可能已经理解了,但我没有写答案,因为我仍然不确定。
可能作者是说当一个非const
左值传递给addName
时,第一个代码中的newName
是const
,非{{1} }} 在第二个代码中,这意味着 如果 const
被传递给另一个函数(或者在其上调用了一个成员函数),那么该函数将需要接受一个 newName
参数(或成为 const
成员函数)。
我的解释是否正确?
但是,我没有看到这在具体示例中有何不同,因为没有在 const
上调用成员函数,也没有将其传递给具有不同重载 {{ 1}} 和非 (不完全是:newName
参数std::vector<T>::push_back
对 const
参数和 const
参数有两个重载,但左值仍然会绑定仅适用于前一个重载...)。
解决方法
在第二种情况下,当一个 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); }
这意味着在两种情况下都选择了 const
的 std::vector<>::push_back
重载。