了解勘误表中有关 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_back
的 const
重载。
在项目 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 theconst
versions, while functions invoked on the uref version's parameter will be theconst
versions only if the argument passed in isconst
. 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_back
的 const
重载。