【问题标题】:How to iterate over a TR1 tuple如何遍历 TR1 元组
【发布时间】:2013-05-03 13:58:55
【问题描述】:

被困在 TR1 领域,对于测试程序,我需要对许多特定类型的对象执行某些操作。我有几个元组类型定义,如下所示:

typedef std::tr1::tuple< bool
                       , signed char
                       , signed short
                       , signed int
                       , signed long long
                       , unsigned char
                       , unsigned short
                       , unsigned int
                       , unsigned long long >  integral_types;

要从每个元组类型创建一个对象。然后我有类似这样的功能模板:

template<typename T>
void invoke_operation_1(T& obj);

需要为元组对象中的所有对象调用这些。

如何在 C++03 中做到这一点?

【问题讨论】:

  • tr1中没有tuple_sizeget吗?
  • Boost.Fusion approach 应该与 C++03 兼容。 manual approach 在这里。
  • @sbi:谁说过关于家庭作业的事? SO问题预计将展示先前的研究。 :) 您的紧迫性无关紧要...
  • 哎呀,我注意到您的问题专门询问了 C++03:不要介意近距离投票。不过,这两个问题可以(应该?)合并为一个问题。

标签: c++ tuples c++03 stdtuple


【解决方案1】:

刚刚在 Bristol 中为 C++14 完成了一项功能来解决这个问题。处理起来并不难。

对于更简单的情况,您可以使用递归模板。虽然没有部分功能专业化等,但它有点混乱。

template<typename Tup, std::size_t N> struct visit_detail {
     template<typename F> static void call(Tup& t, F f) {
         f(std::tr1::get<N>(t));
         return visit_detail<Tup, N+1>::call(t, f);
     }
};
template<typename Tup> struct visit_detail<Tup, std::tr1::tuple_size<Tup>::value> {
    template<typename F> static void call(Tup& t, F f) {}
}

template<typename Tup, typename F> void visit(Tup& t, F f) {
    return visit_detail<Tup, 0>::call(t, f);
}

这里的 f 可以是硬编码的,也可以是参数函数对象或任何你想要的。

【讨论】:

  • 啊,原来有tuple_size。谢谢,我想我可以从那里解决!
  • @DeadMG:哎呀!你能记住 C++14 特性的名称,以供参考吗?
  • N3493 稍作修改
  • @DeadMG:谢谢;看起来很有趣(但希望他们不要在最终的措辞中保留文本“编译时”!)
【解决方案2】:

如果您需要为元组中的每个对象调用相同的模板函数,您可以使用boost::fusion。例如。

template<typename T>
void invoke_operation_1(T& obj)
{
    std::cout << obj << std::endl;
}

struct executor
{
    template<typename T>
    void operator()(T& t) const
    {
        invoke_operation_1(t);
    }
};

typedef boost::tuple< bool
                       , signed char
                       , signed short
                       , signed int
                       , signed long long
                       , unsigned char
                       , unsigned short
                       , unsigned int
                       , unsigned long long >  integral_types;
int main()
{
    integral_types t(true, 0, 1, 2, 3, 4, 5, 6, 7);
    boost::fusion::for_each(t, executor());
    return 0;
}

【讨论】:

  • 我犹豫是否要引入 boost::fusion 只是为了做到这一点,但这看起来真的很方便,所以我还是可以试一试。 executor必须满足什么条件?一些std::tr1::bind() 表达式会起作用吗?使用参数占位符?
  • @sbi 文档说Regular Callable Object 所以绑定表达式应该没问题。
  • @sbi 因为invoke_operation_1 是一个模板而不是一个函数,我怀疑boost::bind 会起作用。至少我找不到任何采用模板模板参数的重载,这里需要。
  • @ArneMertz:你说得有道理,我刚刚遇到了这个问题。 :) 好吧,我想我只需要把它包装成一个函数对象。谢谢,@mkaes!
  • 好吧,因为最后我确实使用了融合,所以我接受了这个答案。感谢所有为此付出努力的人!
【解决方案3】:
template<typename tup, typename N>
struct visit_detailImpl {
    template<typename f>
    static void call(tup& t, f f) {
        f(std::tr1::get<N::value>(t));
        return visit_detailImpl<tup, std::integral_constant<std::size_t, N::value + 1> >::call(t, f);
    }
};
template<typename tup> // end recursion struct
struct visit_detailImpl<tup, std::integral_constant<std::size_t, std::tr1::tuple_size<tup>::value> > {
    template<typename f>
    static void call(tup& t, f f) {}
};
template<typename tup, typename Fn>
void for_each_tup(tup& t, Fn f) {
    return visit_detailImpl<tup, std::integral_constant<std::size_t, 0> >::call(t, f);
}

【讨论】:

  • “被困在 TR1 土地上……”
猜你喜欢
  • 2019-11-16
  • 2018-01-16
  • 1970-01-01
  • 1970-01-01
  • 2020-05-14
  • 2016-05-25
  • 1970-01-01
  • 2015-01-16
  • 1970-01-01
相关资源
最近更新 更多