Контекст : В попытке реализовать копирование и замену идиомы на шаблонный самодельный shared_ptr.У меня возникли проблемы с вызовом этой функции:
template<typename U>
shared_ptr<T>& operator=(shared_ptr<U> rhs)
{
static_assert(std::is_base_of<T, U>::value);
swap(*this, rhs);
return *this;
}
Код лишен ненужного:
Следующий код не компилируется.Строка "x = y" является попыткой использования:
foo<T>& operator=(const foo<U>& ptr) = delete;
Если я удалю / прокомментирую строку удаленных функций.Это означает, что если я не определю их, компилятор сделает это за меня, и код скомпилируется.Тем не менее, специальный член, сгенерированный компилятором, предпочтительнее моего оператора, который не будет вызываться.
template<typename T>
class foo
{
public:
// copy&swap
template<typename U>
foo<T>& operator=(foo<U> rhs)
{
// whatever is needed swap and all
return *this;
}
template<typename U>
foo<T>& operator=(const foo<U>& ptr) = delete;
template<typename U>
foo<T>& operator=(foo<U>&& ptr) = delete;
foo<T>& operator=(foo<T>&& ptr) = delete;
};
int main()
{
foo<int> x,y;
x = y;
return 0;
}
Вопросы :
- Разрешение перегрузкине понятно мне здесь.Почему одна подпись предпочтительнее другой?
- Если функция удалена, я понимаю, что это не «ошибка замещения», но все же это ошибка на уровне сигнатуры, а не внутри тела, почему компилятор прекращает поиск соответствия?
- Какое-нибудь решение, чтобы получить функцию, которая будет вызвана?
Редактировать / ответить
На данный момент это правильная версия:
- Non-templateконструкторы (перемещение / копирование) помечены в явном виде, поэтому назначение foo в foo вызывает версию шаблона.
- Добавлены соответствующие статические утверждения, чтобы преобразование U / T имело смысл
- Аргументы идеально подходят для пересылкиназначать / перемещать внутренние функции
код:
#include <iostream>
template<typename T>
class foo
{
private:
template <typename U> friend class foo;
template<typename U>
void assign(const foo<U>& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated assign function" << std::endl;
this->data = other.data;
}
template<typename U>
void move(foo<U>&& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated move function" << std::endl;
this->swap(*this, other);
}
public:
template<class X, class Y> void swap(foo<X>& left, foo<Y>& right) noexcept
{
std::cout << "templated swap function" << std::endl;
std::swap(left.data, right.data);
}
void swap(foo<T>& left, foo<T>& right) noexcept
{
std::cout << "swap function" << std::endl;
std::swap(left.data, right.data);
}
foo() {}
explicit foo(foo<T>&& other)
{
std::cout << "move constructor foo(foo&& other)" << std::endl;
move(std::forward<decltype(other)>(other));
}
explicit foo(const foo<T>& other)
{
std::cout << "copy constructor foo(const foo& other)" << std::endl;
assign(std::forward<decltype(other)>(other));
}
template<typename U>
foo(foo<U>&& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated move constructor template<typename U> foo(foo<U>&& other)" << std::endl;
move(std::forward<decltype(other)>(other));
}
template<typename U>
foo(const foo<U>& other)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U,T>::value);
std::cout << "templated copy constructor template<typename U> foo(const foo<U>& other)" << std::endl;
assign(std::forward<decltype(other)>(other));
}
// copy&swap
template<typename U>
foo<T>& operator=(foo<U> rhs)
{
static_assert(std::is_base_of<T, U>::value || std::is_convertible<U, T>::value);
std::cout << "templated assignement template<typename U> foo<T>& operator=(foo<U> rhs)" << std::endl;
auto tmp = rhs.data;
rhs.data = reinterpret_cast<U*>(data);
data = reinterpret_cast<T*>(tmp);
return *this;
}
foo<T>& operator=(foo<T> rhs)
{
std::cout << "assignement foo<T>& operator=(foo<T> rhs)" << std::endl;
std::swap(rhs.data,data);
return *this;
}
private:
T * data;
};
int main()
{
foo<int> x,y;
const foo<int>& cy = y;
foo<short> z, w;
x = y;
x = cy;
x = std::move(y);
x = z;
x = std::move(w);
return 0;
}