1

次の単純なコードパターンは、グラフィックプログラミングでは非常に一般的です。
レイヤーの配列を作成し、それらをループします。

struct Layer
{
    int n;
    void operator()(float value)
    {
    }
};

struct AnotherLayer
{
    int n;
    int m;
    void operator()(float value)
    {
    }
};

void process_layers(Layer_t* layer, size_t size, float value) 
{
    for (size_t n = 0; n < size; ++n)
        layer[n](value);
}

Layer a = {1};
Layer b = {2};
AnotherLayer c = {2,3};
typedef std::function < void (float) > Layer_t;
Layer_t layers [] = {a,b,c};
process_layers(layers, sizeof(layers)/sizeof(Layer), 100);

これを変換して、c++11のvaradicテンプレートを使用したいと思います。私がこれをどのように行うことができるかについてのアイデア。これが私が望んでいることです。何か案は?これも可能ですか?

template <int n>
struct Layer
{
    void operator()(float value)
    {
    }
};

template <int n, int m>
struct AnotherLayer
{
    void operator()(float value)
    {
    }
};

template <typename Layer1, typename Layer2, ...>
struct Layers  //process_layers
{
    void operator()(float value)
    {
        for (size_t n = 0; n < SIZEOF(Layer1,Layer2,...); ++n)
            Layer[N]()(value);
    }
};

その後、私はこれを行うことができます。

typedef Layers<Layer<1>, Layer<2>, AnotherLayer<3,8> > funky_layer_t;
typedef Layers<Layer<4>, Layer<5>, Layer<5>, AnotherLayer<6,7> > standard_layer_t;
typedef Layers<funky_layer_t, standard_layer_t> awesome_layer_t;

awesome_layer_t()(100);

注:2番目のアプローチでは、レイヤーを構築するためのすべてのパラメーターがコンパイル時に認識されます。

4

2 に答える 2

1

提供する例は、可変個引数テンプレートを使用して非常に簡単にやり直すことができます。

template<typename Func> void process(Func &&f) {} // base case for zero items

// overload for at least one item
template<typename Func, typename FirstItem, typename... Items>
void process(Func &&f, FirstItem &&fi, Items &&...is) {
    std::forward<Func>(f)(std::forward<FirstItem>(fi));          // f(fi);
    process(std::forward<Func>(f), std::forward<Items>(is)...);  // process(f,is...);
}

Layer a = {1};
Layer b = {2};
Layer c = {3};

process([](Layer &l){ l(100); },
        a, b, c);

また、これにより、オリジナルの不要なコピーがすべて回避されることに注意してください。(もちろん、実行するだけでそれらを回避することもできますがLayer layers[] = {{1},{2},{3}};


後のコメントとコードが、レイヤーのコレクションに対する操作の実行にどのように関連しているかは正確にはわかりません。

コンパイル時に実行する計算は正確には何ですか?


新しい例に合わせるために、process()を変更する必要はまったくありません。必要なのは、各タイプを処理できるファンクターを作成することだけです。(ここでは多形ラムダが役立ちますが、明示的なファンクタータイプを使用して作成する必要があります)

Layer a = {1};
Layer b = {2};
AnotherLayer c = {2,3};

struct TheOperation {
    template<typename T>
    void operator() (T &t) {
        t(100);
    }
};

process(TheOperation(),
    a, b, c);

これが可変個引数テンプレートの構文を修正するためのawesome_layer_t文字起こしですが、まだ何を達成したいのかわからないため、これが適切な方法であるかどうかはわかりません。これは実際にはコンパイル時にsを呼び出すのではなく、実行時にデフォルトで構築され、実行時に再度呼び出されるoperator()オブジェクトの束を設定するだけです。operator()

template <int n>
struct Layer
{
    int operator()(float value)
    {
        std::printf("L %d %e\n",n,value);
        return 0;
    }
};

template <int n, int m>
struct AnotherLayer
{
    int operator()(float value)
    {
        std::printf("AL %d %d %e\n",n,m,value);
        return 0;
    }
};

template <typename... Ls>
struct Layers  //process_layers
{
    int operator()(float value)
    {
        struct Tmp {
            void operator() (...) {}
        };
        Tmp()( Ls()(value)...);
        return 0;
    }
};

typedef Layers<Layer<1>, Layer<2>, AnotherLayer<3,8> > funky_layer_t;
typedef Layers<Layer<4>, Layer<5>, Layer<5>, AnotherLayer<6,7> > standard_layer_t;
typedef Layers<funky_layer_t, standard_layer_t> awesome_layer_t;

int main() {
    awesome_layer_t()(100);
}
于 2012-06-21T20:18:02.330 に答える
0

これは、通常の関数テンプレートを使用して次のように実行できると思います。

/* Base case: If you have no layers to apply, do nothing. */
void executeLayers() {
    // Deliberately empty.
}

/* Recursive step: If you have at least one layer, apply it, then apply the
 * remaining layers.
 */
template <typename Head, typename... Tail> 
void executeLayers(Head head, Tail... tail) {
    head();              // Execute the first layer
    executeLayers(tail); // Execute the remaining layers
}

次に、次のようなことを行うことができます。

executeLayers(layer1, layer2, layer3, layer4, layer5);

お役に立てれば!

于 2012-06-21T20:10:11.003 に答える