В основном у вас есть эти параметры конструктора:
class myclass {
public:
// #1 myclass(const std::string& s) : s(s) {}
// #2 myclass(std::string&& s) : s(std::move(s)) {}
// #3 myclass(std::string s) : s(std::move(s)) {}
// #4 template <typename T> myclass(T&& t) : s(std::forward<T>(t)) {}
std::string s;
};
#3
не может присутствовать с #1
или #2
-> неоднозначным вызовом
и вызовом
std::string s;
myclass A(s);
myclass B(std::move(s));
myclass C("temporary");
myclass D({5, '*'});
Ниже приведено количество конструкторов копирования / перемещения
| A | B | C | D |
------------------------|---|---|---|---|
1 Copy | 1 | 1 | 1 | 1 |
const l-value ref Move | 0 | 1 | 0 | 0 |
Other | 0 | 0 | 1 | 1 |
------------------------|---|-v-|-v-|-v-|
2 Copy | X | 0 | 0 | 0 |
r-value ref Move | X | 1 | 1 | 1 |
Other | X | 0 | 1 | 1 |
------------------------|---|---|---|---|
3 Copy | 1 | 0 | 0 | 0 |
by value Move | 1 | 2 | 1 | 1 |
Other | 0 | 0 | 1 | 1 |
------------------------|---|---|---|---|
4 Copy | 1 | 0 | 0 | X |
Forwarding ref Move | 0 | 1 | 0 | X |
Other | 0 | 0 | 1 | X |
----------------------------------------/
Возможные конфигурации:
#1
только: обрабатывать все случаи, но копировать для временных #1/#2
: (B / C / D будет использовать #2
), поэтому лучшие результаты, за исключением конструкции на месте #3
только: обрабатывать все случаи, но делает дополнительное перемещение #4
только: обработка большинства обычных случаев, лучшие результаты #1/#2/#4
: лучшие результаты (обратите внимание, что #4
) имеет точное совпадение с неконстантным l-значением) #2/#4
: лучшие результаты
Цель #3
- записать только одну перегрузку.
Как видно, ссылка на пересылку (#4
) имеет лучший результат.