在std :: variant

时间:2018-04-05 10:11:23

标签: c++ c++17

我有一组模板类,我想放在std::variant中。以下工作,但相当丑陋(我在变体中有更多的类,有许多模板参数)。

template <typename T>
struct Type1
{ };

template <typename B, typename C>
struct Type2
{ };

template <typename A, typename B, typename C>
using Variant = std::variant<Type1<A>, Type2<B,C>>;

是否可以以类似的方式“隐藏”模板参数? (不编译)

template <typename A>
using Type1T = Type1<A>

template <typename B, typename C>
using Type2T = Type2<B, C>

using Variant = std::variant<Type1T, Type2T>
  

错误:模板参数列表中参数1的类型/值不匹配   对于'模板类std :: variant'

添加typename似乎也不起作用。

1 个答案:

答案 0 :(得分:3)

您无法使用std::variant来执行此操作。您可以使用std::any,但不能visit any

问题是Type1Type2 不是类型,它们是类型模板Type1的实例化存在无穷大,就visit而言,它们都是无关类型

我建议您制作非Type1Base的模板,Type1<T>来自std::variant<std::unique_ptr<Type1Base>, std::unique_ptr<Type2Base>, ...>

编辑 - 甚至template_variant是不可能的,无法恢复所选模板的哪个实例化是活动成员。如果可能的话,那么每个访问者都必须为 每个模板的每个实例化过载带来复杂性。

原始尝试:

您可以编写自己的模板变体,其中包含类似于std::anystd::variant

的成员组合
template<template<class...> class ... Templates>
class template_variant
{
    std::any value;
public:
  // constructors, operator=, etc

  // Observers
    constexpr std::size_t index() const noexcept; // Which template this contains
    const std::type_info& type() const noexcept; // returns the typeid of the contained value

 // Modifiers
    template <template<typename...> class T, class... Args>
    T<Args...>& 
    emplace(Args&&... args)
    {
         value.emplace<T<Args...>>(std::forward<Args>(args)...);
    }

    template <size_t I, class... Args>
    template_variant_alternative_t<I, variant, Args...>& 
    emplace(Args&&... args)
    {
         value.emplace<template_variant_alternative_t<I, variant, Args...>>(std::forward<Args>(args)...);
    }

    void swap( template_variant& rhs ) noexcept;

  // Non-member functions
    friend template <std::size_t I, template<class...> class ... Templates, class... Args>
    constexpr template_variant_alternative_t<I, template_variant<Templates...>, Args...>& 
    std::get(template_variant<Templates...>& v)
    {
        try 
        {
            return std::any_cast<template_variant_alternative_t<I, template_variant<Templates...>, Args...>&>(v.value);
        }
        catch (std::bad_any_cast & e)
        {
            throw bad_template_variant_access(e);
        }
    }
    // and &&, and const&, and const&&

    template <template<class...> class T, template<class...> class ... Templates, class... Args>
    constexpr T<Args...>& 
    std::get(template_variant<Templates...>& v)
    {
        try 
        {
            return std::any_cast<T<Args...>&>(v.value);
        }
        catch (std::bad_any_cast & e)
        {
            throw bad_template_variant_access(e);
        }
    }
    // and &&, and const&, and const&&

    // etc.
};

template <std::size_t I, typename Variant, class... Args>
struct template_variant_alternative;

template <std::size_t I, template<class...> class ... Templates, class... Args>
struct template_variant_alternative<I, template_variant<Templates...>, Args...>
{
    using type = // apply Args... to Ith template in Templates
};

template <std::size_t I, typename Variant, class... Args>
using template_variant_alternative_t = template_variant_alternative<I, Variant, Args...>::type;