2

这是一个使用从Johannes Schaub-litbLuc Danton的答案改编的代码打印元组的简短程序。

#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;
}

print 的第二个参数将始终是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: 在函数'void print(const std::tuple<_Elements ...>&, seq) [with int ...S = {}; T = {double, int, char}]':
tmp5.cpp:23:12: 错误:不完整的类型'std::tuple_size&>' 用于嵌套名称说明符

你知道有什么方法可以在S...没有第二个参数的情况下提供函数print吗?

4

3 回答 3

3

S...问题是如果您不提供第二个函数参数,编译器将无法推断索引序列。当它到达默认参数时,它需要知道是什么S...,所以它不能使用默认参数来确定它。

这可以通过提供print构建索引列表的重载并转发到接受索引列表的重载来解决:

template <typename ...T>
void print(const std::tuple<T...> & tup) {
  print(tup,typename gens<sizeof...(T)>::type());
}
于 2012-05-25T07:30:06.480 回答
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'}
}

你需要换档。

The easiest way to do so would be to provide an overload that would be tasked with passing the second argument. After all, default arguments are just syntactic sugar to avoid writing a forwarding function.

于 2012-05-25T08:43:01.950 回答
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;
}
于 2012-05-25T07:23:23.970 回答