【问题标题】:boost tuple partial iteration?提升元组部分迭代?
【发布时间】:2013-01-04 03:54:57
【问题描述】:

我正在尝试使用 boost 元组来避免一些虚函数开销,但我不能让它工作。我有一个尝试处理输入的“处理程序”向量,一旦其中一个返回 true,我不想调用其余的。

C++11 不可用。

首先,当前的虚拟实现如下所示:

std::vector<Handler*> handlers;

//initialization code...
handlers.push_back(new Handler1);
handlers.push_back(new Handler2);
handlers.push_back(new Handler3);

//runtime code
for(std::vector<Handler*>::iterator iter = handlers.begin();
    iter != handlers.end() && !(*iter)->handle(x); ++iter) {}

由于我在编译时拥有所有类型,因此我希望能够将其表示为一个元组,如下所示:

boost::tuple<Handler1,Handler2,Handler3> handlers;

//runtime code
???
// should compile to something equivalent to:
// if(!handlers.get<0>().handle(x))
//   if(!handlers.get<1>().handle(x))
//     handlers.get<2>().handle(x);

理想情况下,不会有虚函数调用,任何空函数体都会内联。 boost::fusion for_each 似乎几乎可以做到这一点,但我需要短路行为,一旦其中一个处理程序返回 true,其余的就不会被调用。

【问题讨论】:

    标签: c++ boost metaprogramming tuples template-meta-programming


    【解决方案1】:

    你可以试试这样的:

    void my_eval() {}
    template<typename T, typename... Ts>
    void my_eval(T& t, Ts&... ts) {
      if(!t.handle(/* x */))
        my_eval(ts...); 
    }
    
    template<int... Indices>
    struct indices {
      using next_increment = indices<Indices..., sizeof...(Indices)>;
    };
    
    template<int N>
    struct build_indices {
      using type = typename build_indices<N - 1>::type::next_increment;
    };
    template<>
    struct build_indices<0> {
      using type = indices<>;
    };
    
    template<typename Tuple, int... Indices>
    void my_call(Tuple& tuple, indices<Indices...>) {
        my_eval(std::get<Indices>(tuple)...);
    }
    template<typename Tuple>
    void my_call(Tuple& tuple) {
        my_call(tuple, typename build_indices<std::tuple_size<Tuple>::value>::type());
    }
    

    要使用,只需将您的元组传递给my_call

    【讨论】:

    • 看起来不错。如果我要在没有 c++11 的情况下尝试这样做,我应该手动列出 my_eval 和 indices 的情况?
    • @E_G 我想你可以用 Boost.PP 生成它们。虽然不是很有趣。
    • 如果没有 C++11,只需制作一个模板,说明要调用的处理程序总数以及剩余的处理程序数量。 get 区别。递归并专注于 0 个处理程序失败且不递归。
    【解决方案2】:

    简单的模板递归应该生成一个合适的尾调用函数链。

    template< typename head, typename ... rest >
    void apply_handler_step( thing const &arg, std::tuple< head, rest ... > * ) {
        if ( ! handler< head >( arg ) ) {
            return apply_handler_step( arg, (std::tuple< rest ... >*)nullptr );
        } // if handler returns true, then short circuit.
    }
    
    void apply_handler_step( thing const &arg, std::tuple<> * ) {
        throw no_handler_error();
    }
    

    如果你想把函数指针放到元组中的处理程序,那么你会想用一个索引值递归并使用get&lt; n &gt;( handler_tuple ),但原理是一样的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-30
      • 2011-06-02
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 2011-11-27
      • 1970-01-01
      相关资源
      最近更新 更多