Yes, it is possible to define a variant that contains a type that itself contains the same variant type. This is known as a recursive variant. However, because variants must have a fixed size, you can't directly include a variant as one of its own alternative types.
Instead, you need to wrap the recursive variant in a type that allows for dynamic allocation, such as std::unique_ptr
or std::vector
.
Here's an example of a recursive variant that represents a simple expression tree:
#include <memory>
#include <string>
#include <variant>
struct Expr;
using ExprPtr = std::unique_ptr<Expr>;
struct Expr {
std::variant<
int, // integer literal
std::string, // variable name
// unary operation
std::pair<char, ExprPtr>,
// binary operation
std::tuple<ExprPtr, char, ExprPtr>
> value;
};
In this example, Expr
is a struct that contains a variant value
. The variant can hold an integer literal, a variable name (string), a unary operation (a character and a pointer to another Expr
), or a binary operation (two pointers to Expr
s and a character).
Here's how you could use this Expr
 type:
Expr makeIntegral(int i) {
Expr e;
e.value = i;
return e;
}
Expr makeVariable(std::string name) {
Expr e;
e.value = std::move(name);
return e;
}
Expr makeUnary(char op, Expr arg) {
Expr e;
e.value = std::make_pair(
op, std::make_unique<Expr>(std::move(arg)));
return e;
}
Expr makeBinary(Expr left, char op, Expr right) {
Expr e;
e.value = std::make_tuple(
std::make_unique<Expr>(std::move(left)),
op,
std::make_unique<Expr>(std::move(right))
);
return e;
}
// Example usage
Expr exampleExpr = makeBinary(
makeUnary('-', makeVariable("x")),
'+',
makeIntegral(42)
);
This creates an Expr
that represents the expression -x + 42
.
The key points are:
std::unique_ptr
 to allow for recursive containment without requiring a fixed size.makeIntegral
, makeUnary
 etc in the example) to simplify the creation of complex recursive variants.Recursive variants are a powerful tool for representing tree-like data structures in a type-safe way. They are often used in parsers, abstract syntax trees, and similar hierarchical data structures.
Answers to questions are automatically generated and may not have been reviewed.
std::variant
Learn how to store dynamic data types in C++ using unions and the type-safe std::variant