2012-05-25 104 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

没有提供可变参数的默认参数的语法。你可以做的最好的是提供专业化或超载。 –