2016-11-28 93 views
3

我有許多C++結構與許多方法。 C++結構有一個 「默認」實例,我想公開一個使用 這個默認實例的「c」包裝函數。但我也想避免重複所有的原型。使用默認實例爲C++對象創建c-wrappers,並推導出原型

歡迎Alkind 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」中的硬編碼方法真的很煩人,我該如何消除 ?

有沒有更好的方法來做到這一點(函數指針不能用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); 
} 
相關問題