如何使用访问者总结一系列变量?

时间:2018-11-29 05:46:16

标签: c++ c++17 variadic-templates template-meta-programming variant

我正在尝试找到一种使用访问者对std::array的{​​{1}}进行汇总的方法。我已经走了这么远,但是我无法一生都想出如何在没有将std::variant条目添加到访问者lambda列表的开头的情况下推断出访问者类型的问题。

有人知道我可以推断访客中lambda的返回类型的方式,这样我就不必依靠它了?

这就是我现在所拥有的:

void

编辑:我希望结果为#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'; }

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

var startTime = '03:00 AM'; var newStartTime = startTime; var endTime = '05:00 AM'; var minutes=0; var hours=0; var timeArray=[]; var ampm=''; var executing=true; while(executing) { timeArray.push(newStartTime); minutes = Number(minutes) + 30; hours = newStartTime.split(' ')[0].split(':')[0] ampm= newStartTime.split(' ')[1]; if(minutes > 59) { if(Number(hours) > 12) { ampm = newStartTime.split(' ')[1] == 'AM'?'PM':'AM'; hours = '01'; } else { hours = Number(hours) + 1; if(hours.toString().length ==1) { hours = '0' + hours; } } minutes = minutes - 60; } if(minutes.toString().length ==1) { minutes = '0' + minutes; } newStartTime = hours + ':' + minutes+' ' +ampm; if(Number(newStartTime.split(' ')[0].split(':')[0]) > Number(endTime.split(' ')[0].split(':')[0])){ if(newStartTime.split(' ')[1] == endTime.split(' ')[1]) executing = false; } else if(Number(newStartTime.split(' ')[0].split(':')[0]) == Number(endTime.split(' ')[0].split(':')[0])) { if(Number(newStartTime.split(' ')[0].split(':')[1]) >= Number(endTime.split(' ')[0].split(':')[1])) { if(newStartTime.split(' ')[1] == endTime.split(' ')[1]) executing = false; } } } timeArray.push(endTime); 出现时,您对类型的推断太明确了,以至于编译器会为您代劳。

一旦您处于函数autodecltype()的范围内,就可以轻松进行推断(需要创建默认初始化的目标),因为您可以简单地模拟访问者的实际调用

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; } 的非算术版本(这很奇怪)。

答案 1 :(得分:1)

弗兰克的decltype() / std::declval()解决方案的简化(希望如此)。

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

如果愿意,您也可以避免使用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;
}