Сначала я заметил бы, что лучше пометить ваши конструкторы как явные.
Следующим моментом будет то, что лучше изменить первый конструктор в вашем решении, чтобы он использовал ссылку на констант, чтобы избежать копирования lvalue:
// ctors
ThisHasAStringMember(const std::string& str) : m_str(str) {}
ThisHasAStringMember(std::string &&str) : m_str(std::move(str)) {}
Этот подход является оптимальным с точки зрения производительности (у вас будет один вызов конструктора копирования для lvalue и один вызов конструктора перемещения для rvalue), однако в каждом случае довольно скучно реализовывать каждый раз два конструктора.А если у вас N членов - 2 ^ N конструкторов.
Есть несколько альтернатив:
Конструктор Signle, в который вы передаете параметр только по значению.Да, это было неэффективно в C ++ 98, но в C ++ 11, когда вы создаете полную копию - это опция.
ThisHasAStringMember(std::string str) : m_str(std::move(str)) {}
Когда lvalueбудет передан один вызов конструктора копирования и один вызов конструктора перемещения.Когда будет передано значение rvalue, будет два вызова конструктора перемещения.Да, у вас есть один дополнительный вызов конструктора перемещения в каждом из случаев.Но это часто очень дешево (или даже может быть оптимизировано компилятором), а код очень прост.
Один конструктор, в котором вы передаете параметр по rvalue:
ThisHasAStringMember(std::string&& str) : m_str(std::move(str)) {}
Если вы передаете lvalue, вы должны явно скопировать его первым в местевызова, например ThisHasAStringMember (copy (someStringVar)).(здесь copy
- простой метод копирования шаблонов).И у вас все еще будет один дополнительный вызов конструктора перемещения для lvalues.Для значений не будет накладных расходов.Лично мне нравится такой подход: все места, где копируется параметр, являются явными, вы не будете делать случайные копии в местах, критичных к производительности.
Создайте шаблон конструктора и используйте совершенную пересылку:
template <typename String,
std::enable_if_t<std::is_constructible_v<std::string, String>>* = nullptr>
ThisHasAStringMember(String&& str) : m_str(std::forward<String>(str))
{}
У вас не будет никаких накладных расходов как для значений r, так и для значений lvalue, но вам нужно будет создать шаблон конструктора и определить его в заголовке вбольшинство случаев.