2016-11-28 3 views
3

여러 메소드가있는 C++ 구조체가 여러 개 있습니다. C++ 구조체에는 "default"인스턴스가 있고이 기본 인스턴스 을 사용하는 "c"래퍼 함수를 ​​공개하고 싶습니다. 그러나 나는 또한 모든 프로토 타입을 반복하는 것을 피하고자합니다.기본 인스턴스 및 추론 프로토 타입을 사용하여 C++ 객체에 대한 c-wrappers 만들기

알칼리의 C++ 11/14/17 및/또는 매크로 트릭을 환영하지만, 코드 생성기를 사용하고 싶지는 않습니다.

나는 거의 작동하지만, 여전히 몇 가지로 고민하고있다. 세부 사항.

// C++ class that have a "default-instance" /////////////////////////////////// 
struct Foo { 
    int a() { return 1; } 
    int b(int) { return 2; } 
    int c(int, int) { return 3; } 
}; 

Foo *FOO = nullptr; 

// emulating existing c code that can not be changed ////////////////////////// 
typedef int (*ptr_a_t)(); 
ptr_a_t ptr_a = nullptr; 

typedef int (*ptr_b_t)(int); 
ptr_b_t ptr_b = nullptr; 

typedef int (*ptr_c_t)(int, int); 
ptr_c_t ptr_c = nullptr; 

// Wrapper code (almost generic) ////////////////////////////////////////////// 
template <typename T, T> 
struct Proxy; 

// Wrapper class that will use the defualt instance if initialized (FOO is 
// hardcoded). 
template <typename T, typename R, typename... Args, R (T::*mf)(Args...)> 
struct Proxy<R (T::*)(Args...), mf> { 
    static R call(Args... args) { 
     if (FOO) { 
//   ^^^ 
      return ((*FOO).*mf)(args...); 
// HARD-CODED  ^^^^ 
     } else { 
      return -1; 
     } 
    } 
}; 

// Helper function to deduce the Proxy-class (method 'b' is hardcoded) 
template <typename T, typename R, typename... Args> 
auto deduce_args(R (T::*mf)(Args...)) -> Proxy<R (T::*)(Args...), &T::b> { 
// HARD-CODED              ^
    return Proxy<R (T::*)(Args...), &T::b>(); 
// HARD-CODED       ^
} 

// Wrap the methods //////////////////////////////////////////////////////// 
//#define wrap_a decltype(deduce_args(&Foo::a))::call 
#define wrap_b decltype(deduce_args(&Foo::b))::call 
//#define wrap_c decltype(deduce_args(&Foo::c))::call 

int main() { 
    // Test that it works 
    //ptr_a = &wrap_a; // does not work due to hard-coded method 
    ptr_b = &wrap_b; 
    //ptr_c = &wrap_c; // does not work due to hard-coded method 

    return ptr_b(0); 
} 

난 단지 클래스 당 하나의 프록시를 필요로하는 나는, 프록시의 하드 코딩 "FOO"살 수 있지만, 인스턴스 포인터가 템플릿 인수로 전달 될 수 있다면 멋진 일 것이다.

"deduce_args"의 하드 코드 된 메서드는 실제로 anoying입니다. 어떻게 제거 할 수 있습니까? ??

더 좋은 방법이 있습니까 (함수 포인터는 std::function으로 바꿀 수 없습니다).

답변

1

C++ 14 별칭을 사용하면 훨씬 쉽게 원하는 것을 얻을 수있었습니다.

// compile using the "-std=c++14" flag 
// C++ class that have a "default-instance" /////////////////////////////////// 
struct Foo { 
    int a() { return 1; } 
    int b(int) { return 2; } 
    int c(int, int) { return 3; } 
}; 

Foo *FOO = nullptr; 

// emulating existing c code that can not be changed ////////////////////////// 
typedef int (*ptr_a_t)(); 
ptr_a_t ptr_a = nullptr; 

typedef int (*ptr_b_t)(int); 
ptr_b_t ptr_b = nullptr; 

typedef int (*ptr_c_t)(int, int); 
ptr_c_t ptr_c = nullptr; 

// Wrapper code /////////////////////////////////////////////////////////////// 
template <typename T, T, typename P, P> 
struct Proxy; 

template <typename T, typename R, typename... Args, R (T::*mf)(Args...), 
      typename P, P p> 
struct Proxy<R (T::*)(Args...), mf, P, p> { 
    static R call(Args... args) { 
     if (*p) { 
      return ((*(*p)).*mf)(args...); 
     } else { 
      return -1; 
     } 
    } 
}; 

// Wrap the methods /////////////////////////////////////////////////////////// 
#define WRAP(n, obj, m, ptr) \ 
    const auto &n = Proxy<decltype(&obj::m), &obj::m, obj **, &ptr>::call 

WRAP(wrap_a, Foo, a, FOO); 
WRAP(wrap_b, Foo, b, FOO); 
WRAP(wrap_c, Foo, c, FOO); 

int main() { 
    // Test that it works 
    ptr_a = &wrap_a; 
    ptr_b = &wrap_b; 
    ptr_c = &wrap_c; 

    return ptr_b(0); 
}