在C ++中,如何制作一个可以包含相同变体向量的变体?

时间:2018-11-27 15:18:49

标签: c++ vector c++17 self-reference std-variant

我试图制作一个std :: variant,它可以包含相同变体的向量:

class ScriptParameter;
using ScriptParameter = std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >;

我正在重新定义ScriptParameter。它认为可能是因为无法向前声明模板参数吗?

是否有一种方法可以实现也可以包含相同类型的变量的数组的变量?

3 个答案:

答案 0 :(得分:5)

由于前向声明说ScriptParameter是一个类,因此不能使用using别名。但是,这里并没有什么内在的错误,因为vector只是一个指针,所以没有真正的循环依赖。

您可以使用继承:

class ScriptParameter;
class ScriptParameter
    : public std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >
{
public:
    using base = std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >;
    using base::base;
    using base::operator=;
};

int main() {    
    ScriptParameter sp{"hello"};
    sp = 1.0;
    std::vector<ScriptParameter> vec;
    sp = vec;    
    std::cout << sp.index() << "\n";  
}

答案 1 :(得分:1)

在这种情况下,我不确定递归定义是否有意义。它允许在单个ScriptParameter中包含任意多个嵌套向量。 (基本上,我们说的是脚本参数是单个值或整个值的 forest 。)将定义分为两部分可能会更好:

// Represents the value of a single parameter passed to a script
using ScriptParameter = std::variant<bool, int, double, std::string>;

// Represents a collection of one or many script parameters
using ScriptParameterSet = std::variant<ScriptParameter, std::vector<ScriptParameter>>;

或者,如果此处的目标是将参数定义为一组选择中的一个加上这些相同选择的向量,则可以尝试一下模板魔术:

template <class T, class U> struct variant_concat;

template <class... T, class U> struct variant_concat<std::variant<T...>, U>
{
  using type = std::variant<T..., U>;
};

template <class T, class U> using variant_concat_t = typename variant_concat<T, U>::type;

using PrimitiveScriptParameter = std::variant<bool, int, double, std::string>;

using ScriptParameter = variant_concat_t<
  PrimitiveScriptParameter,
  std::vector<PrimitiveScriptParameter>>;

这应该在下面解决Lightness的可用性问题。

答案 2 :(得分:0)

使用类型级别fixed-point operator

#include <vector>
#include <variant>
#include <string>

// non-recursive definition 
template<class T>
using Var = std::variant<int, bool, double, std::string, std::vector<T>>;

// tie the knot
template <template<class> class K>
struct Fix : K<Fix<K>>
{
   using K<Fix>::K;
};

using ScriptParameter = Fix<Var>;

// usage example    
int main()
{
    using V = std::vector<ScriptParameter>;
    ScriptParameter k {V{1, false, "abc", V{2, V{"x", "y"}, 3.0}}};
}