【问题标题】:template looping through tuple模板循环遍历元组
【发布时间】:2015-03-25 18:44:11
【问题描述】:

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

我已尝试以下代码,但无法编译(GCC 4.9 with -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;
}

错误信息非常神秘且冗长,但它基本上说没有匹配的函数调用获取。有人可以向我解释为什么吗? 谢谢。

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

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

【问题讨论】:

  • 请照常进行MCVE!您实际上是如何实例化模板函数的?
  • Pretty-print std::tuple的可能重复
  • 我见过的大多数按位置解包元组的代码都是从sizeof...(Tlist)向下到0,而不是相反。

标签: c++ c++11 variadic-templates stdtuple


【解决方案1】:

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

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 声明。我们总是递归,但是当我们到达元组的末尾时,我们会递归到终止重载。

live example

顺便说一句,如果为std 中定义的两种类型重载&lt;&lt; 是否符合标准,这是不明确的:这取决于std::tuple&lt;int&gt; 是否是“用户定义类型”,标准的条款没有定义。

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

【讨论】:

    【解决方案2】:

    您必须使用专业化或 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&lt;sizeof...(Tlist)&gt; 不早点产生错误,您将无限实例化 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>());
    }
    

    Live example

    【讨论】:

      猜你喜欢
      • 2020-01-12
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多