模板在元组中循环

template looping through tuple

本文关键字:循环 元组      更新时间:2023-10-16

我正在使用可变模板,目前正在尝试为元组实现operator<<

我尝试了以下代码,但它没有编译(GCC 4.9,-std=c++11)。

template<int I, typename ... Tlist>
void print(ostream& s, tuple<Tlist...>& t)
{
    s << get<I>(t) << ", ";
    if(I < sizeof...(Tlist)){
        print<I+1>(s,t);
    }
}
template<typename ... Tlist>
ostream& operator<<(ostream& s, tuple<Tlist...> t)
{
    print<0>(s,t);
    return s;
}

错误消息非常神秘和长,但它基本上表明get没有匹配的函数调用。有人能解释一下为什么吗?谢谢

编辑:这是我使用的模板实例化

auto t = make_tuple(5,6,true,"aaa");
cout << t << endl;

if (blah) {块中的代码}已编译,并且即使条件blah为false,代码也必须有效。

template<bool b>
using bool_t = std::integral_constant<bool, b>;
template<int I, typename ... Tlist>
void print(std::ostream& s, std::tuple<Tlist...> const& t, std::false_type) {
  // no more printing
}
template<int I, typename ... Tlist>
void print(std::ostream& s, std::tuple<Tlist...> const& t, std::true_type) {
  s << std::get<I>(t) << ", ";
  print<I+1>(s, t, bool_t<((I+1) < sizeof...(Tlist))>{});
}
template<typename ... Tlist>
std::ostream& operator<<(std::ostream& s, std::tuple<Tlist...> const& t)
{
  print<0>(s,t, bool_t<(0 < sizeof...(Tlist))>{});
  return s;
}

应该起作用。在这里,我们使用标记调度来控制我们递归调用的重载:如果I是元组的有效索引,则第三个参数为true_type,如果不是,则为false_type。我们这样做而不是if语句。我们总是递归,但当我们到达元组的末尾时,我们递归到终止重载中。

实例

顺便说一句,为std中定义的两个类型重载<<是否符合标准是不明确的:这取决于std::tuple<int>是否是"用户定义的类型",即标准没有定义的子句。

最重要的是,在类型的命名空间中重载该类型的运算符被认为是最佳实践,因此可以通过ADL找到它。但是,根据标准,在std中重载<<是非法的(不能向std中注入新的重载)。在某些情况下,如果发现错误的过载,或者没有发现过载,结果可能会有点令人惊讶。

您必须使用专业化或SFINAE作为分支,即使它没有被使用也会生成实例化:

template<int I, typename ... Tlist>
void print(ostream& s, tuple<Tlist...>& t)
{
    s << get<I>(t) << ", ";
    if(I < sizeof...(Tlist)){
        print<I+1>(s,t); // Generated even if I >= sizeof...(Tlist)
    }
}

因此,如果get<sizeof...(Tlist)>不尽快产生错误,那么您将拥有print的无限实例化。

您可以使用在不递归的情况下编写它

template<std::size_t ... Is, typename Tuple>
void print_helper(std::ostream& s, const Tuple& t, std::index_sequence<Is...>)
{
    int dummy[] = { 0, ((s << std::get<Is>(t) << ", "), 0)...};
    (void) dummy; // remove warning for unused var
}

template<typename Tuple>
void print(std::ostream& s, const Tuple& t)
{
    print_helper(s, t, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}

实例