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でg++3.4.4をコンパイルすると、次のエラーが発生します。

tmp.cpp:12:エラー:タイプT' of template argument0'はテンプレートパラメータに依存します

私は何が間違っているのですか?タイプTであることを示すために、どういうわけか0に注釈を付ける必要がありますか?

前もって感謝します。

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 になります (特殊化のパラメーターに依存します)。2 つの選択肢があります。1 つは依存しないようにすることです。たとえば、T i を int i に変更します。2 つ目は、部分的な特殊化ではなく明示的な特殊化を適用することです。

両方の解決策は他の人によって提供されているため、ここに再投稿するつもりはありません。少なくともあなたはその理由を知っています。標準で定義されています。

于 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< 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 に答える
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";
    }
};

それができるとは思いもしませんでした。とてもプロローグ的でとても素敵です。

于 2011-03-04T14:33:32.673 に答える