2017-03-14 4 views
1

모든 구문 오류는 용납되지 않습니다. 나는 이와 비슷한 설정되어 C++ 코드가 있습니다모호한 식별자가있는 void 포인터 캐스트

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는 NumPy와 배열을 가리키고 있기 때문에이 같은 설정은 코드를하는 모든 유형 (INT, float32, float64 등)의 수, 그리고 ctypes를 통해 파이썬에서 my_func를 호출합니다. 나는 C++이 NumPy 배열이 어떤 타입인지 알지 못하지만 파이썬에서 데이터 타입을 쉽게 얻을 수 있고 그것을 my_func (이 경우 integer 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); 
} 

그래서 결국 거의 같은 일을하는 멋진 스위치 테이블입니다. 인터페이스는 훨씬 깨끗합니다. 내 의견으로는 :)