В пункте 41 Скотт Мейерс описывает следующие два класса:
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;
};
То, что написано в комментариях, верно, даже если это вовсе не означает, что два решения эквивалентны, а некоторые различия действительно обсуждаются в книге.
Однако в исправлениях автор комментирует другое отличие, не обсуждавшееся в книге. :
Другое поведенческое различие между (1) перегрузкой для lvalue и rvalue и (2) шаблоном, использующим универсальную ссылку (uref), заключается в том, что перегрузка lvalue объявляет свой параметр
const
, а подход uref — нет. Это означает, что функции, вызываемые для параметра перегрузки lvalue, всегда будут версиямиconst
, в то время как функции, вызываемые для параметра версии uref, будут версиямиconst
, только если передан аргументconst
. Другими словами, аргументы, отличные отconst
lvalue, могут привести к другому поведению в дизайне перегрузки по сравнению с дизайном uref.
Но я не уверен, что понимаю это.
На самом деле, написав этот вопрос, я, наверное, понял, но я не пишу ответ, так как все еще не уверен.
Вероятно, автор имеет в виду, что когда в addName
передается не-const
lvalue, newName
равно const
в первом коде и не-const
во втором коде, это означает, что если newName
было передано другой функции (или была вызвана функция-член), то эта функция должна была бы принимать const
параметров (или быть const
функцией-членом).
Я правильно интерпретировал?
Однако я не вижу, как это влияет на конкретный пример, поскольку функция-член не вызывается для newName
, и не передается функции, которая имеет разные перегрузки для (не совсем так: const
и не-const
параметровstd::vector<T>::push_back
имеет две перегрузки для const T&
аргументов и T&&
arguments`, но lvalue по-прежнему будет связываться только с прежней перегрузкой...).
std::string
(и вам нужно подумать, нравится вам это или нет). - person Scheff's Cat   schedule 06.01.2021static_assert
в теле, чтобы он принимал толькоstd::string
и/или любой другой желаемый тип. - person Enlico   schedule 06.01.2021newName
передается другой функции, она всегда будет выбирать перегрузкуconst
. Во втором примере, если переданный параметр сам по себе не являетсяconst
, то вместо константной перегрузки будет выбрана неконстантная перегрузка. Суть этой разницы в том, что это была бы молчаливая разница - person Michael Burr   schedule 06.01.2021addName
было что-то вродеnewName.someMethod()
/someFun(newName)
, то в первом примере всегда будет выбраноstd::string::someMethod() const {
/someFun(const std::string&)
, а во втором случае также может быть выбраноstd::string::someMethod() {
/someFun(std::string&)
, если аргумент не являетсяconst
lзначение. - person Enlico   schedule 06.01.2021