Consider this code:
#include <variant>
struct x {
int y;
};
int main() {
std::variant<x> v(std::in_place_type<x>, {3}); /*1*/
return std::get<x>(v).y;
}
This does not compile and neither does when removing the {}
from the line /*1*/
, even though aggregate initialization
x a{3};
x b({3});
works in both "constructor-like" forms. Can I somehow make the std::variant
initializer aware of the possibility of constructing structs using aggregate initialization without having to write boring boilerplate constructors for each struct that may be used in my real-world case?
I would expect this to work, somehow, as per cppreference the two overloads (5) and (6) in question both say
Constructs a variant with the specified alternative T and initializes the contained value with the arguments [...]
I'm using GCC 7 if that matters.
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).
It holds one of several alternatives in a type-safe way. No extra memory allocation is needed. The variant needs the size of the max of the sizes of the alternatives, plus some little extra space for knowing the currently active value. By default, it initializes with the default value of the first alternative.
std::monostate is a class that has exactly one value. It is default constructable and supports all the comparison operations. std::monostate is about as simple of a type as one could concoct. These properties turn out to be useful for writing template code. The first use case is in testing.
std::visit from C++17 is a powerful utility that allows you to call a function over a currently active type in std::variant . In this post, I'll show you how to leverage all capabilities of this handy function: the basics, applying on multiple variants, and passing additional parameters to the matching function.
Maybe it is not exactly what you are asking, but what about explicitly constructing the object instead of relying on type inference?
#include <variant>
struct x {
int y;
};
int main() {
std::variant<x> v(std::in_place_type<x>, x{3});
return std::get<x>(v).y;
}
There is no workaround for this, apart from adding a constructor. The standard mandates this for both overloads you mention, [variant.ctor]19 and [variant.ctor]23 respectively:
Effects: Initializes the contained value as if direct-non-list-initializing an object of type
T
with the argumentsstd::forward<Args>(args)...
.Effects: Initializes the contained value as if direct-non-list-initializing an object of type
T
with the argumentsil, std::forward<Args>(args)...
.
You can always copy or move the object using:
std::variant<x> v(std::in_place_type<x>, x{3});
// or more clear and does the same thing
std::variant<x> v(x{3});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With