2017-03-14 2 views
1

文法上の誤りはありません。 、あいまいな識別子でのキャストポインタのキャスト

template<typename T> 
void addytox(T *x, T *y, int n) 
{ 
    for(int i = 0; i < n; ++i) { 
     x[i] += y[i]; 
    } 
    return; 
} 


void my_func(void *x, void *y, int n, int dtype) 
{ 
    /* Here is where I am unsure of how to do a simple static cast using 
    the dtype identifier. I want to avoid long code using a switch or 
    if/else that would check all possible conditions, for example having 
    code that looks like this: 

     if (dtype == 0) { 
      addytox((int*)x, (int*)y, n); 
     } 
     else if (dtype == 1) { 
      addytox((float*)x, (float*)y, n); 
     } 
     else if (dtype == 2) { 
      addytox((double*)x, (double*)y, n); 
     } 
     else { 
      //Print/log some error... 
      exit; 
     } 

     return; 
    */ 
} 

my_funcは、任意の型(int型、のfloat32、float64型など)の可能性numpyの配列を指しているので、このようなコードも設定がある理由:私はこれと同様のセットアップでC++のコードを持っています私はctypes経由でPythonからmy_funcを呼び出しています。私はC++がNumPy配列がどのような型か分からないことを知っていますが、Pythonでデータ型を簡単に取得し、それをmy_func(この場合は整数dtype)に渡すことができます。私が知りたいのは、その識別子を使うことができれば、関数addytoxを適切な型キャストで一度しか呼び出せないことです。例えば

addytox((cast_type*)x, (cast_type*)y, n)); 

それはC++でこのような何かをすることは可能ですし、もしそうなら、どのように私はそれをやって行くのでしょうか?

ありがとうございます。

+2

短い答えは:いいえ、C + +このように動作しません。 –

+0

ある時点で、正しい関数を呼び出すために実行時に 'dtype'の値をチェックする必要があります。これはコンパイル時に静的に行うことはできません。 – lcs

答えて

2

残念ながら私が問題を理解しているように、テンプレートを使用したコンパイル時の型決定は、実行時には役に立ちません。実行時に呼び出す必要のあるタイプを判断するために、スイッチ型のメカニズムを使用しています。

しかし、私が共有できるいくつかの素晴らしいテンプレートメタプログラミング技術があります。これらは、コンパイルと実行時の型決定のギャップを埋めるのに役立ちます。

// Generic Declaration. Note the default value. 
// For any of the TypeId's not specialized, the compiler will give errors. 
template<int TypeId = 0> 
struct DispatchAddYToX; 

// Specialize for typeId = 0, which let's say is int 
template<> 
struct DispatchAddYToX<0> // Let's say TypeId 0 = int 
{ 
    enum { MyId = 0 }; 
    typedef int MyType; 

    void dispatch(void* x, void* y, int n, int dType) 
    { 
     // Expanded version, for clarity. 
     if(dType == MyId) 
     { 
      // Awriiite! We have the correct type ID. 
      // ADL should take care of lookup. 
      addYToX((MyType*)x, (MyType*)y, n); 
     } 
     else 
     { 
      // If not the correct ID for int, try the next one. 
      DispatchAddYToX<MyId + 1>::dispatch(x, y, n, dType); 
     } 
    } 
}; 

// Specialize for typeId = 1, which let's say is float 
template<> 
struct DispatchAddYToX<1> // Let's say TypeId 1 = float 
{ 
    enum { MyId = 1 }; 
    typedef float MyType; 

    void dispatch(void* x, void* y, int n, int dType) 
    { 
     // Nice and compact version 
     (dType == MyId) ? addYToX((MyType*)x, (MyType*)y, n) : 
          DispatchAddYToX<MyId + 1>::dispatch(x, y, n, dType); 
    } 
}; 

... 
// And so on for the rest of the type id's. 

// Now for a C-style wrapper. 
// Use this with your python hook 
void addYToXWrapper(void* x, void*y, int n, int dType) 
{ 
    // Defaults to start at 0 (int) 
    // Will replace the switch statement. 
    DispatchAddYToX::dispatch(x, y, n, dType); 
} 

最終的には、ほぼ同じことをするファンシースイッチテーブルです。私の意見では、インターフェイスははるかにクリーンです:)

関連する問題