Я пытаюсь следовать совету Скотта Мейерса в пункте 22 книги «Более эффективный C++»: «Рассмотрите возможность использования op=
вместо автономного op
». Он предлагает создать шаблон для operator+
, чтобы все классы, реализующие operator+=
, автоматически получали operator+
:
template<class T>
const T operator+(const T& lhs, const T& rhs)
{
return T(lhs) += rhs;
}
Теперь, в статье 25 книги «Эффективный современный C++», есть пример (стр. 172) сложения матриц, где предлагаются перегрузки operator+
со значениями r, потому что, если вы знаете, что lhs
или rhs
являются значениями r, вы можете использовать их для хранения результате, предотвращая бесполезные копии, возможно, огромных матриц. Поэтому я добавил перегрузки:
template<class T>
T operator+(T&& lhs, const T& rhs)
{
return std::move(lhs += rhs);
}
template<class T>
T operator+(T const& lhs, T&& rhs)
{
return std::move(rhs += lhs);
}
template<class T>
T operator+(T&& lhs, T&& rhs)
{
return std::move(lhs += rhs);
}
Проблема здесь в том, что T&&
является универсальной ссылкой, и в конечном итоге она захватывает все, поэтому я в конечном итоге перехожу от lvalues, что является нежелательным поведением.
Итак, как я могу правильно реализовать шаблон operator+
?
Частичное решение с использованием передачи по значению: я также прочитал пункт 41: "Рассмотрите возможность передачи по значению для копируемых параметров..." из Effective Modern C++, поэтому я попытался написать свою собственную версию следующим образом:
template<class T>
const T operator-(T lhs, T rhs)
{
return lhs -= rhs;
}
Но это упускает возможность оптимизации, когда rhs является значением r, так как в этом случае я не буду использовать rhs для сохранения результата. Так что это только частичное решение.
std::rel_ops
, если это вас не устраивает. - person chris   schedule 24.07.2015operator-
, и я не могу воспроизвести. - person Barry   schedule 24.07.2015rhs += lhs
предполагает, что сложение является коммутативным, что неверно, например, дляstd::string
- person Jonathan Wakely   schedule 24.07.2015