Всем привет,
Обнаружил, что не понимаю, почему вызывается шаблонный конструктор перемещения, вместо нешаблонного в таком коде:
struct Y
{
Y() { std::cout << "default ctor\n"; }
Y(Y&&) { std::cout << "move ctor\n"; }
template<typename T>
Y(T&& y) { std::cout << "move<T> ctor\n"; }
};
int main()
{
Y y1;
Y y2 = y1; // ожидаю move ctor, получаю move<T> ctor
Y y3 = 22; // здесь как и должно быть, move<T> ctor
}
Это как-то неожиданно, так как конструкторы копирования работают ожидаемо:
struct Y
{
Y() { std::cout << "default ctor\n"; }
Y(Y const&) { std::cout << "copy ctor\n"; }
template<typename T>
Y(T const& y) { std::cout << "copy<T> ctor\n"; }
};
int main()
{
Y y1;
Y y2 = y1; // copy ctor
Y y3 = 22; // copy<T> ctor
}
Беглый просмотр разделов "Copy constructors", "Move constructors" и "Memeber templates" на cppreference.com ясности не добавил. В итоге проблему обошел с помощью enable_if, но непонимание причины осталось. Есть только предположение, что тут какие-то тонкости copy elision.
Решение с enable_if:
struct Y
{
Y() { std::cout << "default ctor\n"; }
Y(const Y&) { std::cout << "copy ctor\n"; }
template<typename T>
Y(T const&) { std::cout << "copy<T> ctor\n"; }
Y(Y&&) { std::cout << "move ctor\n"; }
template<typename T,
typename = typename std::enable_if<!std::is_same<Y, typename std::decay<T>::type>::value>::type>
Y(T&& y) { std::cout << "move<T> ctor\n"; }
};
int main()
{
Y y1;
Y y2 = y1; // copy ctor
Y y3 = std::move(y1); // move ctor
Y y4 = true; // move<T> ctor
}
Код:
http://coliru.stacked-crooked.com/a/57c4420a80d33963