Вариант реализации (вариативный шаблон) C++

Я пытаюсь реализовать вариантный класс, но у меня проблема с рекурсивной функцией:

template<typename Visitor, typename... Types>
class VariantVisitor;

template<typename... Types>
class Variant
{
    template <typename V, typename... types>
    friend class VariantVisitor;
public:
    struct holder
    {
        virtual ~holder() {}
    };

    template <typename T>
    struct impl : public holder
    {
        impl(const T& t) : val(t) {}
        T get() const { return val; }
        T val;
    };

    Variant() : mHolder(nullptr) {}

    template <typename T>
    Variant(const T& t) 
    {
        mHolder = new impl<T>(t);
    }

    Variant(const Variant<Types...>& v) : mHolder(nullptr)
    {
        copy<Types...>(v);
    }

    ~Variant()
    {
        delete mHolder;
    }

    template <typename T>
    Variant<Types...>& operator = (const T& t)
    {
        if (!mHolder) {
            mHolder = new impl<T>(t);
            return *this;
        }

        _ASSERT(typeid(*mHolder) == typeid(impl<T>));
        static_cast<impl<T>*>(mHolder)->val = t;
        return *this;
    }

    Variant<Types...> &operator = (const Variant& v)
    {
        copy<Types...>(v);
        return *this;
    }

    template <typename T>
    T Get() const
    {
        _ASSERT(mHolder && typeid(*mHolder) == typeid(impl<T>));
        return static_cast<impl<T>*>(mHolder)->get();
    }

    template<typename T>
    bool Is() const
    {
        return (mHolder && typeid(*mHolder) == typeid(impl<T>));
    }
private:
    template <typename T>
    void copy(const Variant<Types...>& v)
    {
        if (mHolder) delete mHolder;
        impl<T>* ptr = static_cast<impl<T>*>(v.mHolder);
        mHolder = new impl<T>(*ptr);
    }

    template <typename T, typename...types>
    void copy(const Variant<Types...>& v)
    {
        if (!Is<T>())
            return copy<types...>(v);

        copy<T>(v);
    }

    holder* mHolder;
};

Visual C++ 2013 говорит о неоднозначном вызове этой строки:

copy<T>(v);

Я новичок в вариативных шаблонах, но я думаю, что две функции копирования должны различаться по количеству типов, не так ли? Так почему же они могут быть обеими перегрузками? И, конечно же, как я могу это исправить?


person user3813522    schedule 26.02.2015    source источник


Ответы (1)


Пакеты параметров могут быть пустыми. В результате компилятор не может различить

template <typename T> void copy(const Variant& v); // with T = T

а также

template <typename T, typename...types> 
void copy(const Variant& v); // with T = T, types = empty pack

Исправление состоит в том, чтобы вторая версия соответствовала только двум или более аргументам шаблона:

template <typename T, typename T2, typename...types> 
void copy(const Variant& v);

Тело необходимо будет обновить, чтобы использовать copy<T2, types...>(v).

Обратите внимание, что в определении класса Variant вы можете просто написать Variant, и это будет означать Variant<Types...>.

person T.C.    schedule 26.02.2015