【问题标题】:terminating function template recursion终止函数模板递归
【发布时间】:2012-01-24 19:29:21
【问题描述】:

我正在尝试为元组创建打印方法。我检查了其他人指定的解决方案,所有这些都使用辅助结构。我不想使用辅助结构。我觉得下面的代码是有效的,但无法弄清楚。

#include <iostream>
#include <tr1/tuple>

template<typename tupletype,size_t i>
void print< tupletype ,0>(tupletype t)//error: expected initializer before ‘<’ token
{
    std::cout<<std::tr1::get<0><<" ";
}

template<typename tupletype,size_t i>
void print(tupletype t)
{
    std::cout<<std::tr1::get<i><<" ";// no match for 'operator<<' in 'std::cout << get<-78ul>'(my ide actually hangs here!)
    print<tupletype,i-1>(t);
}

int main (int argc, char * const argv[]) {
    std::tr1::tuple<int,float> a(3,5);
    typedef std::tr1::tuple<int,float> tupletype;
    print<tupletype,0>(a);
}

【问题讨论】:

  • 你看到什么样的错误?
  • 没有“模板函数”,但有函数模板
  • 为什么不想使用辅助结构?
  • @Mankarse 在我的私人项目中,我使用了一个类似于 'print' 的函数,它对元组进行操作。但是,该函数已经在深层嵌套类中。我觉得 helper struct 又增加了一步复杂性。 mwigdahl, sbi - 我已经更新了问题

标签: c++ templates tuples


【解决方案1】:

这是一个没有特定辅助结构的:

#include <iostream>
#include <tuple>

template<std::size_t> struct int2type{};

template<class Tuple, std::size_t I>
void print_imp(Tuple const& t, int2type<I>){
  print_imp(t, int2type<I-1>());
  std::cout << ' ' << std::get<I>(t);
}

template<class Tuple>
void print_imp(Tuple const& t, int2type<0>){
  std::cout << std::get<0>(t);
}

template<class Tuple>
void print(Tuple const& t){
  static std::size_t const size = std::tuple_size<Tuple>::value;
  print_imp(t, int2type<size-1>());
}

Live example on Ideone.

【讨论】:

  • 啊,你从超载中解决了这个问题!很棒的发现,+1 来自我。
  • @sbi:重载基本上是部分特化归结为的内容,以及在重载解决和部分排序期间显式特化归结为的内容。 :)
  • 我知道这一点,但我看不出有一种方法可以让重载完成所要求的工作。
  • @Xeo 这是一个很棒的技巧,谢谢。您是否对编译器是否能够完全优化 int2type 的实例化进行任何测试?
【解决方案2】:

首先,您需要在专门化之前声明函数模板

template<typename tupletype,size_t i>
void print(tupletype t);

但是,它仍然行不通,因为您不能部分特化函数模板——而您正在尝试做的是部分特化。

因此,做你想做的事情的唯一方法是依靠类模板部分特化

template<typename tupletype,size_t i>
struct printer;

template<typename tupletype>
struct printer< tupletype ,0> {
  static void print(tupletype t)
  {
    std::cout<<std::tr1::get<0>(t)<<" ";
  }
};

template<typename tupletype,size_t i>
struct printer {
  static void print(tupletype t)
  {
    std::cout<<std::tr1::get<i>(t)<<" ";
    printer<tupletype,i-1>::print(t);
  }
};

template<typename tupletype,size_t i>
void print(tupletype t)
{
  printer<tupletype,i>::print(t);
}

您为什么不想这样做?

【讨论】:

  • 请注意,您可以在 C++11 中部分特化函数模板
  • @Paul 不,你不能。这没有改变。
  • 是的,没错,您不能在 C++11 中部分专门化函数模板。很抱歉,我把它与默认模板参数混淆了(你可以在 C++11 中像使用类一样在函数上使用它)
【解决方案3】:

此代码无效。您不能部分专门化功能模板,这是您想做的事情所必需的。你真的需要一个辅助结构。

【讨论】:

    【解决方案4】:

    你有几个问题。

    你需要在专业化之前声明模板。

    对于另一个您忘记将 tupletype 实例传递给 ::get

    但是,最大的问题是您正在尝试对功能模板进行部分特化,这是标准不允许的(搜索 SO 或 google 以了解原因)。

    现在解决(某种程度上)您的要求:

    请注意,要创建通常有用的编译时递归,您需要对输入对象(即:您的元组类型)和一个索引进行模板化,该索引将用于递归迭代输入中的元素.模板递归需要部分特化来定义退出条件。你不能用函数模板来做到这一点,但你可以用类来做到这一点——因此,使用结构。

    现在,在特定 的意义上,您实际上可以在不使用结构的情况下实现您想要的。为此,您需要避免部分专业化......因此我们需要完全专业化。 (在我被否决之前 - 我完全承认这个解决方案在一般意义上不是很有用 - 但 OP 想要避免使用结构,所以我做到了!)

    通过使函数只采用特定的元组类型,我们可以只有一个模板参数 - 索引。因此,我们可以完全特化函数模板来获得退出条件:

    #include <iostream>
    #include <tr1/tuple>
    
    typedef std::tr1::tuple<int,float> tupletype;
    
    template<size_t i>
    void print(tupletype t)
    {
        std::cout << std::tr1::get<i>(t) << " ";
        print<i-1>(t);
    }
    
    template<>
    void print<0>(tupletype t)
    {
        std::cout << std::tr1::get<0>(t) << " ";
    }
    
    int main()
    {
        tupletype a(3,5);
    
        print<1>(a);
    }
    

    【讨论】:

    • “专业化”不一定是“部分专业化”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多