Собственно, вопроса особенного нет, просто информация, хотя если у кого-то есть версия, почему это происходит welcome.
VC2015 спокойно предпочитает для lvalue вызов шаблонного перемещающего конструктора rvalue (**), игнорируя перегрузку шаблонного копирующего конструктора c const lvalue (*)
class foo {
public:
foo() {}
~foo() {}
foo(const foo&) {}
foo(foo&&) {}
foo& operator=(const foo&) { return *this; }
foo& operator=(foo&&) { return *this; }
template<typename T> explicit foo(const T& x) {} // (*)
template<typename T> explicit foo(T&& x) {} // (**)
};
TEST(FooTest, VC2015) {
std::string s("hello");
foo f(s); // ok for VC2015, template<typename T> explicit foo(T&& x) will be called
}
Проблема решается путем добавления третьей перегрузки для lvalue:
template<typename T> explicit foo(T& x) {} // (*)
Между тем, нешаблонные версии конструкторов работают как и ожидалось (компилятор отлавливает ошибку):
class boo {
public:
boo() {}
~boo() {}
boo(const boo&) {}
boo(boo&&) {}
boo& operator=(const boo&) { return *this; }
boo& operator=(boo&&) { return *this; }
// explicit boo(const std::string& x) {}
explicit boo(std::string&& x) {}
};
TEST(BooTest, VC2015) {
std::string s("hello");
boo f(s); // error C2664: '`anonymous-namespace'::boo::boo(const `anonymous-namespace'::boo &)': cannot convert argument 1 from 'std::string' to 'std::string &&'
}