提升元组部分迭代?

时间:2013-01-04 03:54:57

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

我正在尝试使用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,其余的就不会被调用。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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< n >( handler_tuple ),但原理是相同的。

相关问题