В C ++, как сделать вариант, который может содержать вектор того же варианта? - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь создать std :: вариант, который может содержать вектор того же варианта:

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

Я получаю переопределение ScriptParameter.Возможно, это потому, что параметр шаблона не может быть объявлен вперёд?

Есть ли способ получить вариант, который также может содержать массив одинаковых типизированных вариантов?

Ответы [ 3 ]

0 голосов
/ 27 ноября 2018

Я не уверен, что рекурсивное определение имеет смысл в этом случае.Он допускает произвольное количество вложенных векторов внутри одного ScriptParameter.(По сути, мы говорим, что параметр сценария является либо одним значением, либо целым лесом значений.) Лучше разделить определение на две части:

// 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 ниже.

0 голосов
/ 27 ноября 2018

Используйте тип уровня оператор с фиксированной точкой .

#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}}};
}
0 голосов
/ 27 ноября 2018

Поскольку прямое объявление говорит, что 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";  
}
...