如何使用访问者对一系列变体求和?

How to sum over an array of variant using a visitor?

我正在尝试找到一种方法来使用访问者对 std::variantstd::array 求和。我已经走到这一步了,但我一辈子都想不出如何在不在访问者 lambda 列表的头部包含 void 条目的情况下推断出访问者的类型。

有谁知道我可以推断出访问者中 lambda 的 return 类型的方法,这样我就不必依赖它了吗?

这是我现在得到的:

#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';
}

编辑:我希望结果为 constexpr

感谢您的帮助。

auto 让编译器为您处理时,您的类型推断过于明确。

一旦你在函数的范围内 decltype()std::declval() 就可以轻松地进行推理(需要创建默认初始化的目标),因为你可以简单地模拟实际调用访客。

template<typename... T, typename S, typename... Ss, size_t N>
constexpr auto summation(const Visitor<S, Ss...> &visitor, const std::array<std::variant<T...>, N> &array) {

    using Result = decltype(std::visit(visitor, std::declval<std::variant<T...>>()));
    static_assert(std::is_arithmetic_v<Result>);

    Result sum{};
    for (const auto &a: array)
        sum += std::visit(visitor, a);
    return sum;
}

我实际上更喜欢这种风格,因为错误的调用实际上会产生一个合理的错误消息,而不是 "function not found"。那是除非你有非算术版本的 accumulate() 你正试图 sfinae 反对(这会很奇怪)。

Frank 的 decltype()/std::declval() 解决方案的简化(我希望)。

使用decltype()/std::declval(),你不需要知道SSs...T...;您只需要 visitor 的模板类型 Varray.

的模板类型

您也可以避免 static_assert(),如果您愿意,只需编写

即可重新启用 SFINAE
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;
}