Reputation: 4766
I have a struct that contains a variant
.
I want to write a member function for that struct that should run code depending on which type variant currently holds.
However, I have issues making it compile.
I don't want to use more "template shenanigans" like using a separate struct to define operator(T&)
since it pollutes the syntax even more.
Here is an example:
struct Data {
std::variant<int, double> var;
//Into this function,multiple lambdas should be passed for cases that the user wants to handle
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
std::visit(std::forward<Funcs>(funcs)...,var);
}
};
int main() {
Data d;
d.var = 4;
//variant holds int and lambda provided that takes int&, execute it:
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
d.var = 0.0;
//variant holds double but no lambda passed that takes a double, hence nothing happens:
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
}
and I even don't know what the compiler wants from me: https://godbolt.org/z/oM4584anf
Upvotes: 2
Views: 2814
Reputation: 66230
Your problem is that std::visit()
needs a "visitor" that must handle every type of the std::variant
.
However, I have issues making it compile. I don't want to use more "template shenanigans" like using a separate struct to define operator(T&) since it pollutes the syntax even more.
There is nothing complicated.
You can simply add a trivial struct (with deduction guide) as follows (and as proposed in the cppreference std::visit()
page)
template<class... Ts> struct overloaded : Ts...
{ using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
Then, given that you want that your std::visit()
return void
, you can add, in your apply()
method, a generic-do-nothing lambda
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
std::visit(overloaded{ // <-- pass through overloaded
[](auto const &){}, // <-- and add this generic lambda
std::forward<Funcs>(funcs)...},var);
}
Now the first apply()
call
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
should compile calling the supplied lambda because is a better match (given that d
contains an int
) and the second call compile calling the do-nothing generic lambda, because the generic lambda is a better match for a double
.
Upvotes: 9