I have a question about using a generic visitor with exclusion of non-equal types. Suppose I have the following:
using StorageT = std::variant<std::vector<int>, std::vector<double>>;
StorageT process_data(const StorageT &lhs, const StorageT &rhs) {
return std::visit([&](auto &&l, auto &&r){
return kernel(l, r); // some templated kernel
},
lhs, rhs);
}
Externally, I verify that the underlying stored type for variants lhs
and rhs
match. I'd like to write a generic visitor, without code being generated for all combinations of lhs
and rhs
where the underlying variant types are not the same.
As it stands, all combinations of the two underlying variant types are generated. Inside the lambda, I could write
if constexpr(std::is_same_v<Tl, TR>) {
return kernel( ... );
} else {
// Do nothing
// static_assert(false);
// Throw exception
}
Since all combinations of lhs
and rhs
are generated, the above code either a) complains about no return on the mismatch of types, b) fails due to the static assert, or c) generated a code path for an exception which will never be thrown (due to an external check of the types).
What is the best way to avoid code generation for all cases where the underlying types for lhs
does not equal rhs
?
Just visit one of the types and use that to determine the other type:
StorageT process_data(const StorageT &lhs, const StorageT &rhs) {
return std::visit([&](auto &&l){
auto &r = std::get<std::remove_cvref_t<decltype(l)>>(rhs);
return kernel(l, r);
},
lhs);
}