I'm trying to find a way to sum over an std::array
of std::variant
using a visitor. I've gotten this far, but I can't for the life of me figure out how to deduce the type of the visitors without including a void
entry at the head of my visitor lambda list.
Does anyone know of a way I can deduce the return type of the lambdas in the visitor so that I don't have to rely on this?
Here's what I've got right now:
#include <array>
#include <iostream>
#include <string_view>
#include <type_traits>
#include <variant>
using namespace std::literals::string_view_literals;
template<typename... Base>
struct Visitor: Base ... {
using Base::operator()...;
};
template<typename... T>
Visitor(T...) -> Visitor<T...>;
// There has to be a better way to deduce Result than what I'm doing...
template<typename... T, typename S, typename... Ss, size_t N, typename Result = typename std::result_of_t<S()>>
constexpr std::enable_if_t<std::is_arithmetic_v<Result>, Result>
summation(const Visitor<S, Ss...> &visitor, const std::array<std::variant<T...>, N> &array) {
Result sum{};
for (const auto &a: array)
sum += std::visit(visitor, a);
return sum;
}
int main() {
constexpr Visitor visitor {
// This first entry should be unnecessary, I would think:
[]() -> double { return 0; },
[](double d) -> double { return d + 3.4; },
[](int i) -> double { return i - 2; },
[](std::string_view s) -> double { return s.size(); }
};
constexpr std::array<std::variant<int, double, std::string_view>, 5> arr{9.0, 9, 3, 5.2, "hello world"sv};
constexpr auto val = summation(visitor, arr);
std::cout << val << '\n';
}
Edit: I'd like the result to be constexpr
.
Thanks for any help.
A simplification (I hope) of the Frank's decltype()
/std::declval()
solution.
Using decltype()
/std::declval()
, you don't need to know S
, Ss...
and T...
; you simply need a template type V
for visitor
and a template type for array
.
You can also avoid the static_assert()
, if you prefer, re-enabling SFINAE simply writing
template <typename V, typename A,
typename R = decltype(std::visit(std::declval<V>(), std::declval<A>().at(0)))>
constexpr std::enable_if_t<std::is_arithmetic_v<R>, R>
summation(V const & visitor, A const &array)
{
R sum{};
for (const auto &a: array)
sum += std::visit(visitor, a);
return sum;
}