「テンプレート関数ポインタ」を達成するために他にどのように?

StackOverflow https://stackoverflow.com/questions/560322

質問

これは手動で行うの手間をかけずに、テンプレート関数ポインタのセットを確立することは可能ですか?ここで何が一体私が話しているものを説明するための例です。

のは、私は動的に切り替えるできるようにしたいと思い、私は2つの実装(WRITE0とWRITE1)を持っているの頻繁に呼び出される関数「書き込み」を持っているとしましょう。これらの書き込み関数は、引数の型にテンプレート化されています。これを行う1つの方法は、単に内部的にif文を使用して、テンプレートのフロントエンド機能の書き込みを()することです。

これは私のニーズに十分に高速であることが判明したが、今私はそれを用いた関数ポインタ(楽しみのためだけに)行うことができるかどうか疑問に残っていました。このアプローチの問題点は、関数ポインタを設定することは面倒であるということです。基本的に、書き込みの理想を達成するための他の方法があります()は、条件(ダイレクト静的派遣)なし?

(他の「ルール」:私は、ライト()メソッドを持っているメッセージクラスを変更することはできません、と私はMSGS用のアダプタでのMSGを置き換えるために使用するサイトコードを変更することはできません)

FWIW、私はこの記事

役に立ちましたか?

解決

あなたがプログラムの実行中に前後にログ機能を切り替えたい場合は、

、私はあなたが手動で各タイプの関数ポインタを設定することがあると思います。

それだけで、起動時にロギング機能を選択するだけで十分ですが

は、それがさえ機能が後で呼び出されるどのタイプについて知らなくても、完全に一般的な方法で行うことができます:

// writer functions
template<typename T> void write0(T msg) { std::cout << 0; };
template<typename T> void write1(T msg) { std::cout << 1; };

// global flag
bool use_write0;

// function pointers for all types
template<typename T>
struct dispatch {
   typedef void (*write_t)(T);
   static write_t ptr;
};

// main write function
template<typename T>
inline void write(T msg) {
   (*dispatch<T>::ptr)(msg);
}

// the fun part
template<typename T>
void autoinit(T msg) {
   if (use_write0)
      dispatch<T>::ptr = &write0<T>;
   else
      dispatch<T>::ptr = &write1<T>;
   // call again for dispatch to correct function
   write(msg);
}

// initialization
template<typename T>
typename dispatch<T>::write_t dispatch<T>::ptr = &autoinit<T>;

// usage example
int main(int argc, char **argv) {
   use_write0 = (argc == 1);
   write("abc");
   return 0;
}

Tへの最初の呼び出しが使用されるべき書き込み機能を決定write<T>()各タイプについて。その後の呼び出しは、直接その機能に関数ポインタを使用します。

他のヒント

また、ドンClugstonの FastDelegates のヘッダを使用することができます。一切実行時のオーバーヘッドを生成しないと、本当にデリゲートをオブジェクト指向。それらを使用するための構文は完璧ではないですが、それは生の関数ポインタをいじるよりも少し簡単です。

なぜあなたは、関数ポインタの配列を使用していない?

#include <iostream>
using namespace std;

template<typename T> void write0(T msg) { cout << "write0: " << msg.name() << endl; }
template<typename T> void write1(T msg) { cout << "write1: " << msg.name() << endl; }

template<typename T> struct WriteSelector
{
    static void(* const s_functions[])(T msg);
};
template<typename T> void(* const WriteSelector<T>::s_functions[])(T msg)=
{
    &write0<T>,
    &write1<T>
};

unsigned write_index=0;
template<typename T> void write(T msg)
{
    WriteSelector<T>::s_functions[write_index](msg);
}


struct MsgA { const char *name() { return "MsgA"; } };
struct MsgB { const char *name() { return "MsgB"; } };
struct MsgC { const char *name() { return "MsgC"; } };
struct MsgD { const char *name() { return "MsgD"; } };

void Test()
{
    write(MsgA());
    write(MsgB());
    write(MsgC());
    write(MsgD());
}

int main()
{
    Test();
    write_index=1;
    Test();
    return 0;
}
WRITE0 / WRITE1選択とMSGA / B / C ....選択:

書き込みの変動の2つの車軸があります。

概念的意味しますwrite機能のN×Mの実装を必要とします。書き込み実装が追加された、またはメッセージタイプが追加された場合はもちろん、これはRESPにつながります。 MまたはN余分な機能を追加します。

は、両方の車軸のためには、静的または動的な多型を使用してそれらを実装するかどうかを選択できます。静的な多型は、テンプレートを使用したり、関数のオーバーライドを使用して行うことができます。

これは、各クラスのMライト機能を持つN個の要素クラス階層を作成することによって行うことができます。しかし、それはすぐにメンテナンスの悪夢になるだろう。メッセージの内容は、実行時多型でない限り。しかし、問題は、メッセージのための静的な多型についてです。

ランタイム多型があるため、あまりにも精巧で除外される(そして、あなたがオーバーライドの冗長性を減少させることになる、仮想テンプレート機能を持つことができない)ので、我々は、コンパイルにランタイム情報を変換し、少し型派遣ルーチンを実装する必要があります-time情報ます。

具体的には:作家に使用して(Tmainと呼ばれる例では)主なアクションをテンプレート化し、「本当の」mainから右のテンプレート引数でそれを呼び出す

これは、「グローバル」の選択変数の使用を省略し、まだオブジェクト指向かつ簡潔です。

    // twodimensionalpolymorph.cpp
    //

    #include <iostream>

    using namespace std;

    class Write0 {
        public: 
        template< typename tMsg > 
        void operator()( /*const*/ tMsg& msg ) { cout << "write0: " << msg.name() << endl; };
    };

    class Write1 {
        public: 
        template< typename tMsg > 
        void operator()( /*const*/ tMsg& msg ) { cout << "write1: "<< msg.name() << endl; };
    };

    struct MsgA { const char *name() { return "MsgA"; } };
    struct MsgB { const char *name() { return "MsgB"; } };
    struct MsgC { const char *name() { return "MsgC"; } };
    struct MsgD { const char *name() { return "MsgD"; } };

    // the Tmain does the real action
    //
    template< typename Writer >
    int Tmain( Writer& write, int argc, char** args ) {

        write( MsgA() );
        write( MsgB() );
        write( MsgB() );
        write( MsgD() );

        return 0;
    }

    // the main merely chooses the writer to use
    //
    int main( int argc, char** args ) {

        if( argc==1 )
            return Tmain( Write0(), argc, args);
        else
            return Tmain( Write1(), argc, args);

    }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top