Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++, how to make a variant that can contain a vector of of same variant?

I a trying to make a std::variant that can contain a vector of the same variant:

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

I am getting ScriptParameter redefinition. It think it is possibly because a template parameter cannot be forward declared?

Is there a way to achieve a variant that could also contain an array of same typed variants?

like image 346
JeffV Avatar asked Nov 27 '18 15:11

JeffV


People also ask

What is std :: variant in C++?

The class template std::variant represents a type-safe union. An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value (this state is hard to achieve, see valueless_by_exception).

What is boost variant?

Boost. Variant, part of collection of the Boost C++ Libraries. It is a safe, generic, stack-based discriminated union container, offering a simple solution for manipulating an object from a heterogeneous set of types in a uniform manner.

Does STD variant require RTTI?

Since this function is specific to a given type, you don't need RTTI to perform the operations required by std::any .

Does STD variant allocate?

According to cppreference ::std::variant must not allocate dynamic memory. As with unions, if a variant holds a value of some object type T, the object representation of T is allocated directly within the object representation of the variant itself. Variant is not allowed to allocate additional (dynamic) memory.


2 Answers

Since the forward declaration says ScriptParameter is a class, you can't use using alias. However, nothing is inherently wrong here, since vector is only a pointer, there is no real circular dependency.

You can use inheritance:

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";  
}
like image 88
llllllllll Avatar answered Sep 19 '22 21:09

llllllllll


Use the type level 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}}};
}
like image 20
n. 1.8e9-where's-my-share m. Avatar answered Sep 19 '22 21:09

n. 1.8e9-where's-my-share m.