6

我正在尝试使用模板在 C++ 中展开循环,如下所示。

#include <iostream>

template< class T, T i >
struct printDown {
    static void run(void) {
        std::cout << i << "\n";
        printDown< T, i - 1 >::run();
    }
};

template< class T >
struct printDown< T, 0 > {
    static void run(void) {
        std::cout << 0 << "\n";
    }
};

int main(void) {
    printDown< int, 10 >::run();
    return 0;
}

当我在 Cygwin 中编译 w/g++ 3.4.4 时,出现以下错误。

tmp.cpp:12:错误:类型T' of template argument0' 取决于模板参数

我究竟做错了什么?我是否需要以某种方式注释 0 以说明它是 T 类型?

提前致谢。

4

6 回答 6

5

你试过int i代替T i吗?

于 2011-03-04T00:51:11.797 回答
4

为什么会发生这种情况?从 14.5.5/8 开始,

— 对应于专门化的非类型实参的模板形参的类型不应依赖于专门化的参数。[ 例子:

template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error

—结束示例]

因此,当您应用部分特化时,0 的类型是 T(取决于特化的参数)。有两种选择,一种是使其不依赖,例如将T i 更改为int i,第二种是应用显式特化而不是部分特化。

这两种解决方案都已经被其他人给出了,所以我不会在这里重新发布它们。至少你知道原因。它是由标准定义的。

于 2011-03-04T01:05:05.187 回答
1

正如您的实现所指出的那样,phooji它存在一个小问题:它会快速生成一长串调用,这将使编译器迅速窒息。

您可以通过使用二进制分解实现稍微复杂的版本来解决此问题。我也会让它在仿函数上通用,因为我很懒。

// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;

我们需要一个辅助模板,它保留要传递的参数的偏移量

template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;

template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
  static F run(F f) { return f; }
};

template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
  static F run(F f) { f(OffSet); return f; }
};

template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
  static F run(F f) {
    F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
    return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
  }
};

你可以UnrolledLoop简单地实现:

template <Functor F, unsigned N>
struct UnrolledLoop
{
  static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}

请注意,您可以为更多值N(例如 3、4)提供专门化,以便在编译器上更好。

于 2011-03-04T08:57:02.860 回答
0

将其添加到您的示例中怎么样:

template struct printDown< int, 0 >{
    static void run(void) {
    std::cout << 0 << "\n";
} };

如果事先不知道 T 的类型,编译器不能自动将 0 转换为 int。

于 2011-03-04T00:53:11.773 回答
0

才发现这个。显然可以做这样的事情。

template< class T, T i, bool b = (i == 0) >
struct printDown {
    static void run(void) {
        std::cout << i << "\n";
        printDown< T, i - 1 >::run();
    }
};

template< class T, T i >
struct printDown< T, i, true > {
    static void run(void) {
        std::cout << 0 << "\n";
    }
};

我不知道可以做到这一点。非常Prologish & 非常好。

于 2011-03-04T14:33:32.673 回答
0

您可以将参数设为类型参数来解决此问题

template< bool > struct bool_ { };

template< class T, T i, typename = bool_<true> >
struct printDown {
    static void run(void) {
        std::cout << i << "\n";
        printDown< T, i - 1 >::run();
    }
};

template< class T, T i >
struct printDown< T, i, bool_<i == 0> > {
    static void run(void) {
        std::cout << 0 << "\n";
    }
};

int main(void) {
    printDown< int, 10 >::run();
    return 0;
}

通过这种方式,您可以在部分专业化中指定您想要的任何条件。

于 2011-03-04T14:50:18.753 回答