2013-12-21 63 views
4

在C++ 11中,可變參數模板允許用任意數量的參數調用一個函數,並且省略號運算符允許該可變參數函數對這些參數中的每一個做某事,即使這些參數不是相同的東西爲每個參數:Can/should /將省略號適用於元組嗎?

template<typename... Types> 
void dummy(Types... ts){} //dummy to allow function calls via parameter expansion 

template<typename... Numerics> 
void increment5(Numerics&... ns){ 
    dummy(ns+=5 ...); //parameter expansion (need space after 5 because 5. is decimal) 
    //it means "dummy(ns_first+=5, ns_second+=5, ns_third+=5, etc.)" 
} 

int main(){ 
    int i = 0; 
    float f = 1.1; 
    std::valarray<int> vi = {1,2,3}; 

    increment5(i,f,vi); 

    cout 
     <<i<<endl 
     <<f<<endl 
     <<vi[0]<<' '<<vi[1]<<' '<<vi[2]<<endl; 

} 

如果我們定義一個異質值陣列(不同數量的類型的列表),我們希望能夠做同樣的事(能夠將號碼添加到每元件)。但是我們必須將元素存儲爲元組。

//a class of numbers, possibly different 
template<typename... Numerics> 
class HeterogeneousValueArray{ 
private: 
    tuple<Numerics...> inner; 
public: 
    //initialize the internal vector 
    HeterogeneousValueArray(Numerics... ns): inner(ns...) {} 
}; 

//Given this function, we don't have to explicitly give the types 
//when constructing a HVA 
template<typename... Numerics> 
HeterogeneousValueArray<Numerics...> HeterogeneousValueArray(Numerics... ns){ 
    return HeterogeneousValueArray<Numerics...>(ns); 
} 

要調用上面的increment5操作符,我們需要做一個元組展開。 As I understand it, this solution would require defining helper functions for each function I want to write.我們也可以遞歸地定義增量5,但是這又一次需要每個函數有兩個函數體。

我相信編程語言應該努力設計一個允許我們編寫我們想寫的代碼。所以這就是我想要寫的。

template<typename... Numerics> 
void increment5(HeterogeneousValueArray<Numerics...>& hva){ 
    increment5(hva.inner...); //expand a tuple 
} 

或者這個。

template<typename... Numerics> 
void increment5(HeterogeneousValueArray<Numerics...>& hva){ 
    dummy((hva.inner+5)...); //expand a tuple 
} 

換句話說,我想把一個元組作爲參數包。

當然,「編寫你想寫的代碼」是理想的,並且在實現任何功能時可能會出現問題。什麼樣的問題會使這種功能無法按預期工作(模棱兩可?),或者它會如何踩在現有代碼或功能的腳趾上?或者...它已經存在於C++ 14中嗎?

+1

我不認爲你需要編寫一個幫助函數,用於你想調用擴展元組的每個函數。你可以使用一個帶有元組和函數對象(包括函數指針)的函數模板,並將函數對象應用到元組的每個元素。 – dyp

+0

哦,是的,我不認爲你也可以使用那樣的重載函數。在這種情況下,你將不得不做一個幫手功能。 – leewz

+0

對於重載函數,您可以在C++ 1y中使用通用lambda。它也是一種輔助函數,但具有lambdas的通常優點(局部性,簡單寫)。 – dyp

回答

5

用於創建解決方案的基本工具存在於C++ 14,但你確實需要間接通過的一個額外的輔助功能的額外級別,類似於答案您鏈接到:

template<typename Tuple, std::size_t... I> 
void 
_increment5(Tuple& t, std::index_sequence<I...>) 
{ 
    dummy(std::get<I>(t) += 5 ...); 
} 

template<typename... Numerics> 
void 
increment5(HeterogeneousValueArray<Numerics...>& hva) 
{ 
    _increment5(hva.inner, std::index_sequence_for<Numerics...>()); 
} 

std::index_sequence_for<T1, T2, T3>std::index_sequence<0, 1, 2>類型的別名,所以當與包擴展一起使用時,它會爲參數包的元素創建一系列索引。然後可以通過幫助函數將該序列的索引推斷爲另一個參數包,因此包擴展std::get<I>(t)...將擴展I以提取元組的每個元素。

所添加index_sequence到C++ 14還增加示出用於對函數對象的元組的通用apply功能,這將允許什麼@DyP在上述評論建議的示例的提案:

template<typename... Numerics> 
void 
increment5(HeterogeneousValueArray<Numerics...>& hva) 
{ 
    apply(hva.inner, [](auto& n) { n += 5; }); 
} 

apply函數不在C++ 14中(但C++ 17的版本號爲proposed),所以你需要自己編寫它,例如通過從C++ 14草案複製它。

最接近的建議,可以直接允許你想要的是N3728但這並沒有被接受,所以不會在C++ 14中。

+0

你不需要C++ 14,你可以在C++ 11中創建自己的'std :: index_sequence'。所有必需的語言功能都在。 – Yankes

+0

是的,我知道,我寫了將它添加到標準的建議:)但在C++ 14中,您不必這樣做,實現提供了它。 –

+0

N3728似乎是我想要的(不是元組,而是存儲的參數包),但不能解釋向元組添加語法是否會導致問題。 – leewz