Вариант реализации (вариативный шаблон) 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);
Я новичок в вариационных шаблонах, но думаю, что следует различать две функции копирования по числу типов, не так ли? Так почему они могут быть оба перегрузки? И, конечно, как я могу это исправить?
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...>
,