разрешение перегрузки шаблонного специального элемента (operator =) - PullRequest
0 голосов
/ 27 мая 2018

Контекст : В попытке реализовать копирование и замену идиомы на шаблонный самодельный 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;
}

1 Ответ

0 голосов
/ 27 мая 2018
  1. operator=(const foo&) отличается только квалификатором cv и будет предпочтительнее шаблона
  2. = delete, что запрещает operator=(const foo&).Это не только останавливает компилятор от его генерации.

Это должно сделать это:

#include <tuple>
#include <iostream>

template<typename T>
class foo
{
private:
    template <typename U> friend class foo;

    foo& assign(T rhs)
    {
        std::swap(data, rhs);
        return *this;
    }

public:


    template<typename U>
    foo& operator=(const foo<U>& rhs)
    {
        return assign(rhs.data);
    }

    template<typename U>
    foo& operator=(foo<U>&& rhs)
    {
        return assign(std::move(rhs.data));
    }

    foo& operator=(const foo& rhs)
    {
        return assign(rhs.data);
    }

    foo& operator=(foo&& rhs)
    {
        return assign(std::move(rhs.data));
    }

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;
}

Edit1: добавлен элемент Member и вызов swap.

Edit2: изменено присвоение для взятия T по значению вместо foo<T> добавлено назначение перемещения

ПРИМЕЧАНИЕ: Теперь используется конструктор преобразованияT при назначении foo другого типа (U)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...