使用 C++ 中的模板展开循环具有部分专业化

发布于 2024-10-20 05:43:20 字数 671 浏览 8 评论 0原文

我正在尝试使用模板在 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 中使用 g++ 3.4.4 进行编译时,出现以下错误。

tmp.cpp:12: 错误:输入 T' of 模板参数0'取决于 模板参数

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

提前致谢。

I'm trying to use templates to unroll a loop in C++ as follows.

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

When I compile w/ g++ 3.4.4 in Cygwin, I get the following error.

tmp.cpp:12: error: type T' of
template argument
0' depends on
template parameter(s)

What am I doing wrong? Do I need to somehow annotate the 0 to say that it's of type T?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

仲春光 2024-10-27 05:43:20

您是否尝试过 int i 而不是 T i

Have you tried int i instead of T i?

冷月断魂刀 2024-10-27 05:43:20

为什么会出现这种情况?从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,二是应用显式特化而不是部分特化。

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

Why this happens? From 14.5.5/8,

— The type of a template parameter
corresponding to a specialized
non-type argument shall not be
dependent on a parameter of the
specialization. [ Example:

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

—end example ]

Therefore when you apply partial specialization, the type of 0 is T (dependent on a parameter of the specialization). There are two choices, one is to make it none dependent, e.g., change T i to int i, and second is to apply explicit specialization rather than partial specialization.

Both solutions have been given out by others, so I'm not gonna to repost them here. At least you know the reason. It's defined by standard.

请爱~陌生人 2024-10-27 05:43:20

正如 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)对编译器更好。

As pointed out by phooji your implementation suffers from a small issue: it quickly generates a long list of calls, which will make compilers choke quickly.

You could work around this by implementing a slightly more complicated version, using binary decomposition. I'll make it generic on a functor too, cause I am lazy.

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

We need a helper template, which keeps an offset of the parameter to pass

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

And you can implement UnrolledLoop simply:

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

Note that you could provide specialization for more values of N (3, 4 for example) to be nicer on the compiler.

小糖芽 2024-10-27 05:43:20

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

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

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

What about adding this to your example:

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

The compiler cannot cast 0 to int automatically without knowing T's type in advance.

瑶笙 2024-10-27 05:43:20

刚刚发现这个。显然人们可以做这样的事情。

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 和很不错。

Just found this out. Apparently one can do something like this.

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

I had no idea that could be done. Very Prologish & very nice.

过度放纵 2024-10-27 05:43:20

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

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

这样您就可以在部分特化中指定所需的任何条件。

You can make the parameter a type parameter to work this around

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

This way you can specify any conditions you want in the partial specializations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文