变体实现(可变参数模板)C ++

时间:2015-02-26 01:12:56

标签: c++ templates c++11 variant variadic

我正在尝试实现变体类,但我遇到了递归函数的问题:

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

我是variadic模板的新手,但我认为应该区分两种类型的复制函数,不应该吗?那么为什么它们都可以重载?当然,我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

参数包可以为空。因此,编译器无法区分

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...>