2

私は定期的なタスクを実行する独自のMCUを持っており、その「ダウンタイム」を他のことで埋めたいと思っています。通常、これは大きなswitchステートメントを使用して実行されますが、これは問題ありませんが、もっとエレガントな方法があるかどうか疑問に思っています。これは、この特定のデバイスのコードで非常に一般的なパターンであるため、一般的なメソッドがあると便利です。

だから私は次のコードを書きました、そしてそれは動作します、しかしそれは現在関数をインライン化しません。

    static InterlacedFunction searchFunctions[4] = {...};

    typedef int (* const InterlacedFunction)(int);

    template<const int numberOfWovenFunctions> int SendPacketWithWovenFunctions(
            int * packet,
            const int packetLength,
            InterlacedFunction (&functions)[numberOfWovenFunctions],
            int firstArgument = 0)
    {
            int returnFromLastWoven = (numberOfWovenFunctions != 0) ? (functions[0])(firstArgument) : 0;

            SendData(packet[0]);

            for(int i = 1; i < packetLength; i++)
            {
                    if(i < numberOfWovenFunctions)
                            returnFromLastWoven = (functions[i])(returnFromLastWoven);
                    SendData(packet[i]);
            }
            return returnFromLastWoven;
    }

私は何かが足りないのですか、Clangがこれらの関数をインライン化することは不可能ですか、それともClangにはまだ最適化がありませんか?

4

1 に答える 1

2

一般に、コンパイラーは、コンパイル時に既知である場合でも、関数ポインターを介して呼び出しをインライン化することに積極的ではありません。

この場合、コンパイラがループをnumberOfWovenFunctions反復のブロックに展開するか、インライン関数のスイッチを生成するのに十分賢いことに依存していますが、どちらもありそうにありません。

イディオムをより一般的にしたい場合は、再帰テンプレートを使用して行うことができます(c ++ 11可変個引数テンプレートがない場合は作成するのが面倒です)が、実際に単純化を構成するかどうかはおそらく疑わしいです。

つまり、ウーブン関数ポインター値のリストでテンプレートを作成し、各レベルでウーブン関数を呼び出して結果を保存し、sendPacketを呼び出して、保存された結果を使用して次のテンプレートレベルに再帰します。(未テスト)のようなもの:

template <InterlacedFunction ... args>
struct WovenFunc;

//Base case - send remaining packets
template <> 
struct WovenFunc<>{
    static int call(int value, int * packet, size_t count){
        for(size_t c = 0; c < count; ++c) SendData(packet[c]);
        return value;
    }
};

//Recursive case - send packets + weave functions
template <InterlacedFunction arg, InterlacedFunction ... args>
struct WovenFunc<arg, args...>{
    static int call(int initial, int * packets, size_t count){
        int r = arg(initial);
        SendData(packets[0]);
        if(count)
            return WovenFunc<args...>::call(r, packets + 1, count - 1);
    }
};

そして、送信で:

typedef WovenFunc<Woven1, Woven2, Woven3> WovenSend
WovenSend::call(returnFromLastWoven, packets, packetLength);

明らかに、あなたが作ることができるのはより一般的です。

于 2013-02-02T10:03:48.167 に答える