Wanted to use a std::map<std::string, std::variant<A, B>> my_map where A and B are classes that have similar constructors (take a yaml object as argument), but I cannot figure out how to actually insert a key/value pair into such a map.
a similar minimum example
class A {
public:
A(int x): x_(x) { std::cout << "A" << std::endl;}
int x_;
void print() {std::cout << 2 * x_ << std::endl;}
};
class B {
public:
B (int x): x_(x) {std::cout << "B" << std::endl;}
int x_;
void print() {std::cout << 5* x_ << std::endl; }
};
int main()
{
using var_t = std::variant<A, B>;
std::map<std::string, var_t> my_map;
var_t v {std::in_place_type<A>, 3};
//my_map["a"] = v; // none of these work
//my_map.emplace("a", v);//
my_map.insert({"a", v});
std::visit([](auto&& var) { var.print();}, my_map["a"]);
}
Results in this
usr/local/include/c++/13.1.0/tuple:2254:9: error: use of deleted function 'std::variant<_Types>::variant() [with _Types = {A, B}]'
2254 | second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I understand that this is due to the fact that the the variant types have ambiguous/non-default constructors so when it tries to build with the key "a" the compiler cannot figure out the correct constructor to use.
What's the correct way to use and add pairs to such a structure ?
The issue is not with insertion, but with use of
operator[]. This operator creates default-initialised object when key is not found in map, and yourstd::varianthas no default constructor*.Change
to
and both of these initialisations will work:
* Variant only has default constructor if the first alternative can be default constructed. In your case,
Ahas no default constructor, sostd::variantwill not be default-constructible.