2012-05-25 184 views
2

這是一個簡短的程序,用於使用代碼根據Johannes Schaub - litbLuc Danton的答案打印元組。C++ 11可變參數模板:默認索引數組值

#include <iostream> 
#include <tuple> 

template<int ...> 
struct seq { }; 

template<int N, int ...S> 
struct gens : gens<N-1, N-1, S...> { }; 

template<int ...S> 
struct gens<0, S...> { 
    typedef seq<S...> type; 
}; 

template <int ...S, typename ...T> 
void print(const std::tuple<T...> & tup, seq<S...> s) { 
    int res[] = { (std::cout << std::get<S>(tup) << " ", 0)... }; 
    std::cout << std::endl; 
} 

int main() { 
    std::tuple<double, int, char> tup(1.5, 100, 'c'); 
    print(tup, gens<std::tuple_size<decltype(tup)>::value >::type()); 
    return 0; 
} 

打印的第二個參數將總是始終gens<N>::type(),其中N是元組的大小。我試圖避開了第二個參數通過提供一個默認參數打印:

template <int ...S, typename ...T> 
void print(const std::tuple<T...> & tup, seq<S...> s = gens<std::tuple_size<decltype(tup)>::value >::type()) { 
    int res[] = { (std::cout << std::get<S>(tup) << " ", 0)... }; 
    std::cout << std::endl; 
} 

然而,結果是一個編譯器錯誤:

tmp5.cpp: In function ‘void print(const std::tuple<_Elements ...>&, seq) [with int ...S = {}; T = {double, int, char}]’:
tmp5.cpp:23:12: error: incomplete type ‘std::tuple_size&>’ used in nested name specifier

你知道有什麼方法可以提供S...無函數的第二個參數如print

回答

3

沒有,沒有。

事實上,這個問題並不侷限於可變參數模板,它出現在所有模板函數中:參數的模板類型不能從其默認值推導出來。

template <typename T> 
void func(T = 0) {} // expected-note {candidate template ignored:\ 
             couldn't infer template argument 'T'} 

int main() { 
    func(); // expected-error {no matching function for call to 'func'} 
} 

您需要切換檔位。

最簡單的方法是提供一個負責傳遞第二個參數的重載。畢竟,默認參數只是語法糖,以避免寫一個轉發函數。

+0

鏗鏘樣式的評論真的很討厭。 –

+0

@ JohannesSchaub-litb:我必須承認,我非常喜歡這種呈現編譯錯誤的方式(當時只有幾個人......) –

+0

太糟糕了。我正在處理異構元組(元組,array ,...>',其內容可以全部發送到模板函數'template array f(array )'以產生新的我想現在,我將把序列設置爲一個常量表達式,以避免在第二個參數中出現重複的「gens」代碼。 – user

1

有可能是一個更好的辦法,但我能想到的最簡單的方法是增加額外的間接級別:

#include <iostream> 
#include <tuple> 

template<int ...> 
struct seq { }; 

template<int N, int ...S> 
struct gens : gens<N-1, N-1, S...> { }; 

template<int ...S> 
struct gens<0, S...> { 
    typedef seq<S...> type; 
}; 

template <typename ...T, int ...S> 
void print_impl(const std::tuple<T...> & tup, seq<S...>) { 
    int res[] = { (std::cout << std::get<S>(tup) << " ", 0)... }; 
    std::cout << std::endl; 
} 
// Pass args to real implementation here 
template <typename ...T> 
void print(const std::tuple<T...> & tup) 
{ 
    print_impl(tup, typename gens<sizeof...(T)>::type()); 
} 

int main() { 
    std::tuple<double, int, char> tup(1.5, 100, 'c'); 
    print(tup); 
    return 0; 
} 
+0

我同意,但是這與提供打印序列一樣困難......我想知道是否有方法向可變參數類型提供默認參數? – user

3

的問題是,編譯器有沒有辦法來推斷索引列S...如果您沒有提供第二個函數參數。當它到達默認參數時,它需要知道S...是什麼,所以它不能使用默認參數來確定它。

這可以通過提供建立索引列表,並轉發給接受索引列表過載print過載來解決:

template <typename ...T> 
void print(const std::tuple<T...> & tup) { 
    print(tup,typename gens<sizeof...(T)>::type()); 
} 
+0

我明白你的意思了。但是有什麼辦法可以爲可變參數模板分配默認參數嗎?我將創建其中的幾個函數,並希望儘可能簡單地聲明和調用它們... – user

+2

沒有提供可變參數的默認參數的語法。你可以做的最好的是提供專業化或超載。 –