How should one match a specialized version of a variant?
Let's say I have a variant that can hold a bunch of different types of values (say I got them from parsing a JSON or similar).
using Value = std::variant<std::monostate, int, double, std::string>;
Let's also say that I have another variant that is a strict subset of the first.
using Numeric = std::variant<int, double>;
Given a Value
, what is the best way for me to specialize for Numeric
? I've tried std::visit
, which does work if I do concrete overloads...
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
void test(Value something) {
std::visit(overloaded{
[](Numeric) { std::cout << "Number" << std::endl; },
[](std::string) { std::cout << "Other" << std::endl; },
[](std::monostate) { std::cout << "Other" << std::endl; },
},
something);
}
int main(int argc, char const *argv[]) {
Value nothing{};
Value some_int{10};
Value some_float{10.0};
Value some_string{"hello"};
test(nothing); // Other
test(some_int); // Number
test(some_float); // Number
test(some_string); // Other
return 0;
}
... but as you can see, I end up duplicating the other lambdas. However, it breaks if I use an auto
'd default:
void test(Value something) {
std::visit(overloaded{
[](Numeric) { std::cout << "Number" << std::endl; },
[](auto) { std::cout << "Other" << std::endl; },
},
something);
}
// Elided
test(nothing); // Other
test(some_int); // Other
test(some_float); // Other
test(some_string); // Other
I've also tried using std::get_if
but that just throws a bunch of errors at me (It seems that it can't tell that the auto
'd lambda should exclude the values in Numeric
)
void test(Value something) {
if (auto numeric = std::get_if<Numeric>(&something)) {
std::cout << "Number";
} else {
std::cout << "Other";
}
}
/usr/include/c++/11/variant:1176:42: error: static assertion failed: T must occur exactly once in alternatives
1176 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/11/variant:1176:42: note: ‘std::__detail::__variant::__exactly_once<std::variant<int, double>, std::monostate, int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >’ evaluates to false
Is my only option explicitly listing out either the types I want to match on, or the types I don't want to match on? That would involve a lot of duplication, not to mention I would need to keep it synchronized with the variant.
0 comment threads