template<class T> B& operator=(T&&)
{ std::cout << "T&& (T is " << typeid(T).name() << ")\n"; return *this; }
не является оператором назначения перемещения, потому что это шаблон.Начиная с N4140, [class.copy] / 19
Объявленный пользователем оператор присваивания перемещения X::operator=
является нестатической не шаблонной функцией-членом класса X
с ровно одним параметром типа X&&
, const X&&
, volatile X&&
или const volatile X&&
.
Вы определили шаблон оператора присваивания, который принимает ссылка для пересылки .В строке
b1 = b2;
шаблон operator=(T&&)
лучше соответствует оператору назначения копирования (B& operator=(const B&)
), поскольку T
будет выводиться как B&
, а преобразование квалификации const
не выполняется.требуется.
Если вы замените вызовы на typeid
, которые отбрасывают ссылки, на Boost.TypeIndex, это станет очевидным.
template<class T> B& operator=(T&&)
{
std::cout << "T&& (T is " << boost::typeindex::type_id_with_cvr<T>().pretty_name() << ")\n";
return *this;
}
Live demo
Выходные данные изменяются на
const A&
B is B
T&& (T is B&)
Если вы не хотите, чтобы operator=(T&&)
был выбран, вы можете ограничить его, чтобы он сбрасывался из разрешения перегрузки, если T=B
template<class T, std::enable_if_t<not std::is_same<B, std::decay_t<T>>{}, int> = 0>
B& operator=(T&&)
{
std::cout << "T&& (T is " << boost::typeindex::type_id_with_cvr<T>().pretty_name() << ")\n";
return *this;
}
(вы можете использовать is_convertible
вместо is_same
, если задействовано наследование)
Live демо