Reputation: 10125
std::visit
supports multiple input variants. The code, however, should handle all combinations of the types from those variants.
Is there a way to skip not "meaningful" combinations?
for example:
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::variant<int, float, char> v1 { 's' };
std::variant<int, float, char> v2 { 10 };
std::visit(overloaded{
[](int a, int b) { },
[](int a, float b) { },
[](int a, char b) { },
[](float a, int b) { },
[](float a, float b) { },
[](float a, char b) { },
[](char a, int b) { },
[](char a, float b) { },
[](char a, char b) { }
}, v1, v2);
return 0;
}
is there a chance to implement only several important combinations, and "leave" the rest? (of course right now the compiler will report nasty error if you forget to implement one combination...)
maybe generic lambdas?
std::visit(overloaded{
[](int a, int b) { },
[](int a, float b) { },
[](int a, char b) { },
[](float a, int b) { },
[](auto a, auto b) { }, // <<
}, v1, v2);
That works, but I wonder if there's some better solution?
Update: Here's the playground with the solutions mentioned in the answers: http://coliru.stacked-crooked.com/a/78d9f2f25789bad2
Upvotes: 6
Views: 728
Reputation: 75924
Yes, generic lambdas are a very good solution. Your proposed solution literally works ad litteram.
Usual overload rules apply.
[](auto a, auto b)
is equivalent in this sense with
template <class T1, class T2> auto foo(T1 a, T2 b) const;
Anything that doesn't match exactly one of the non-templated overloads will call the generic lambda.
You can mix things up a bit by providing something like [] (int a, auto b)
and [] (auto a, auto b)
. Still usual overload rules apply.
Or mix things up even more with []<class T>(T a, T b)
(since C++20)
Upvotes: 7
Reputation: 26372
Another option would be to change overloaded
to something like this:
template<class... Ts>
struct overloaded_or_no_op : Ts...
{
using Ts::operator()...;
template<class... Us>
void operator()(const Us&...) const { }
};
template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;
Upvotes: 3