【问题标题】:Using filter on vector of variant在变体向量上使用过滤器
【发布时间】:2021-09-13 14:11:23
【问题描述】:

我正在尝试迭代过滤(按类型)std::vector<std::variant<T...>>。 我遇到的问题是std::get 是重载函数(并且有许多我需要输入的隐式模板参数)所以我需要将它转换为特定的东西。

这看起来很难看,所以我尝试将holds_alternativeget 组合成一个函子,该函子返回filter(对于holds_alternative)和transform(对于get)视图的视图。 那是行不通的。

问题:

  • 我可以做我想做的事而不提供我的结构并且不需要指定std::get 重载的丑陋强制转换,丑陋需要指定std::holds_alternativestd::get 的所有模板参数吗?
  • 如果对上一个问题的回答是否定的:为什么我的尝试不起作用

注意:

我的代码不会像std::get 那样尝试正确处理const&&,我可以只在const l 值上工作。

我的code

#include <algorithm>
#include <iostream>
#include <ranges>
#include <variant>
#include <vector>

struct Red {
  int x = 0;
};

struct Green {
  int x = 1;
};

struct Blue {
  int x = 2;
};

using Color = std::variant<Red, Green, Blue>;

template <typename T> struct engaged_t {
  template <typename... Ts>
  constexpr bool operator()(const std::variant<Ts...> &variant) {
    return std::holds_alternative<T>(variant);
  }
};

template <typename T> inline constexpr auto engaged = engaged_t<T>{};

template <typename T> struct variant_get_t {
  template <typename... Ts>
  constexpr decltype(auto) operator()(std::variant<Ts...> &variant) {
    return std::get<T>(variant);
  }
};

template <typename T> inline constexpr auto variant_get = variant_get_t<T>{};

template <typename T> struct variant_filter_t {};

template <typename T>
inline constexpr auto variant_filter = variant_filter_t<T>{};

template <typename R, typename T>
decltype(auto) operator|(const R &r, variant_filter_t<T>) {
  return r | std::views::filter(engaged<T>) |
         std::views::transform(variant_get<T>);
}

int main() {
  std::vector<Color> colors{Red{}, Green{}, Blue{}, Green{}};
  // does not compile
  // for (const auto green: colors | variant_filter<Green>){
  //   std::cout << std::get<Green>(green).x << std::endl;
  // }

  // kaboom if we try to do anything, just to show we can pipe colors to
  // variant_get
  for (const auto bad_green : colors |
                                  std::views::transform(variant_get<Green>) |
                                  std::views::take(0)) {
  }
  // we can also pipe colors to engaged
  for (const auto bluev : colors | std::views::filter(engaged<Blue>)) {
    std::cout << std::get<Blue>(bluev).x << std::endl;
  }
  // and if we manually doe what variant_filter should_do that also seems to
  // work
  for (const auto blue : colors | std::views::filter(engaged<Blue>) |
                             std::views::transform(variant_get<Blue>)) {
    std::cout << blue.x << std::endl;
  }
}

【问题讨论】:

  • 所以你想要一个 functorfilter 后跟 transform 视图?
  • 这是很多问题。你想回答哪一个?
  • @Jarod42 我想要一种作曲方法 | std::views::filter(参与) | std::views::transform(variant_get) 无需键入 两次。
  • @Barry:好吧,如果我的假设是正确的,如果不使用自定义结构,我就不能很好地写出我想要的东西我想知道为什么仿函数不起作用,因为当我“手动”执行它时,它似乎工作。
  • 您在参数上的variant_get_t::operator() 中错过了const

标签: c++ c++20 std-ranges


【解决方案1】:

通过将const R&amp; 更改为转发参考R&amp;&amp;(并修复错字),它可以工作:

template <typename R, typename T>
decltype(auto) operator|(R&& r, variant_filter_t<T>) {
  return r | std::views::filter(engaged<T>)
           | std::views::transform(variant_get<T>);
}

int main() {
  std::vector<Color> colors{Red{}, Green{}, Blue{}, Green{}};
  for (const auto green: colors | variant_filter<Green>){
     std::cout << green.x << std::endl;
  }
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 2012-05-12
    相关资源
    最近更新 更多