【问题标题】:Iterate over tuple of functors in c++11在 c++11 中迭代函子元组
【发布时间】:2018-06-06 16:41:37
【问题描述】:

我有一个 std::tuple 的仿函数(数量未知),它们都应该返回相同的类型,所以类似于:

typedef functor std::function<bool()>;
std::tuple<functor, functor, functor...> functors;

我想迭代仿函数,评估每个成员,直到找到成功的成员,否则失败。如何在 c++11 中实现这一点?

【问题讨论】:

  • 请发布您尝试过的内容。
  • 严格来说是 C++11?没有 C++14?
  • @max66 不幸的是正确
  • @R Sahu 我没有尝试太多,尝试了一点模式匹配来获取元组的头部和尾部,但运气不佳。有 tuple_cat 可以合并元组,但没有什么可以很好地拆分它们,所以很棘手。
  • 一个模板函数,它接受int index 模板参数和元组,并执行return get&lt;index&gt;(t)() || ThisFunction&lt;index+1&gt;(t); 加上为index &gt;= tuple_size&lt;T&gt;::value 启用的重载SFINAE 并无条件返回false。类似的东西。

标签: c++ c++11 stl variadic-templates template-meta-programming


【解决方案1】:

不是特别有创意,但是...

如果创建foo()函数如下

template <typename ... Args>
bool foo (std::tuple<Args...> const & tf)
 { return bar<0>(tf); }

该调用,从模板索引 0 开始,以下几个模板(启用/禁用 SFINAE)替代函数

template <std::size_t I, typename ... Args>
typename std::enable_if<(I >= sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const &)
 { return false; }

template <std::size_t I, typename ... Args>
typename std::enable_if<(I < sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const & tf)
 { return baz(std::get<I>(tf)) || bar<I+1U>(tf); }

还有一个额外的 baz() 函数来调用单个函子

bool baz (functor const & f)
 { return f(); }

我想你可以得到你想要的。

以下是一个完整的工作示例

#include <tuple>
#include <iostream>
#include <functional>

using functor = std::function<bool()>;

bool baz (functor const & f)
 { return f(); }

template <std::size_t I, typename ... Args>
typename std::enable_if<(I >= sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const &)
 { return false; }

template <std::size_t I, typename ... Args>
typename std::enable_if<(I < sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const & tf)
 { return baz(std::get<I>(tf)) || bar<I+1U>(tf); }

template <typename ... Args>
bool foo (std::tuple<Args...> const & tf)
 { return bar<0>(tf); }

bool f0 () { std::cout << "f0 "; return false; }
bool f1 () { std::cout << "f1 "; return false; }
bool f2 () { std::cout << "f2 "; return false; }
bool f3 () { std::cout << "f3 "; return false; }
bool f4 () { std::cout << "f4 "; return true; }
bool f5 () { std::cout << "f5 "; return false; }
bool f6 () { std::cout << "f6 "; return false; }
bool f7 () { std::cout << "f7 "; return false; }
bool f8 () { std::cout << "f8 "; return false; }
bool f9 () { std::cout << "f9 "; return false; }

int main ()
 {
   auto tf = std::make_tuple(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);

   foo(tf);
 }

显然您可以避免使用baz(),只需按如下方式调用函子

 return std::get<I>(tf)() || bar<I+1U>(tf);

但您对 Args... 类型的检查松了。

【讨论】:

  • 或将std::tuple 替换为std::vector 并删除所有不必要的代码
  • @Slava - 是的,但这并不好笑:-((我在开玩笑,我同意:如果 OP 可以,使用 std::vector,而不是 std ::tuple,非常可取)。
【解决方案2】:

只需使用适当的容器 - std::vector 而不是 std::tuple

using functor = std::function<bool()>;
using functors = std::vector<functor>;

我认为如何迭代 std::vector 很明显

【讨论】:

  • 我有点不准确,解析器都返回“兼容”类型,以便它们可以提升为某种类型,但它们不一定完全相同。另外我想使用元组来保持静态分配。
  • 然后,如果您阅读有关 std::tuple_cat en.cppreference.com/w/cpp/utility/tuple/tuple_cat 的文档,它会为您提供有关如何迭代元组的确切示例
猜你喜欢
  • 2015-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多