2013-01-04 96 views
1

我想使用boost元組來避免一些虛函數的開銷,並且我不能使它工作。我有一個嘗試處理輸入的「處理程序」向量,一旦其中一個返回true,我不想調用其餘的。boost元組迭代?

首先,目前虛擬實現看起來是這樣的:

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,其餘的不會被調用。

回答

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

+0

看起來不錯。如果我要在沒有C++ 11的情況下嘗試這樣做,我應該手動列出my_eval和indices的情況? –

+1

@E_G你可以用Boost.PP生成它們,我假定。雖然不是很有趣。 – Pubby

+0

如果沒有C++ 11,只需要創建一個模板,調用多少個處理程序來調用總數以及剩下多少個處理程序。 「獲得」差異。遞歸併專門處理剩下的0個處理程序失敗並且不進行遞歸。 – Yakk

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),但原理是一樣的。