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
std::visit from C++17 is a powerful utility that allows you to call a function over a currently active type in std::variant .
std::variant variant is a value type that's used to represent a choice of types. The class takes a list of types, and the variant will be able to contain one value of any of those types. It is often referred to as tagged union, because similar to a union, it can store multiple types, with only one present at a time.
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)
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...>;
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