2009-07-15 58 views
6

我基本上希望生成一個通用C函數的包裝,而不必手動指定類型。所以我有一個固定的原型回調,但我需要在封裝基於包裝函數的類型做一些特殊的代碼...所以基本上我想在類模板中使用靜態方法包我的功能,以符合標準的接口,例如:非模板參數...這是一個模板! (C++)

// this is what we want the wrapped function to look like 
typedef void (*callback)(int); 
void foobar(float x); // wrappee 

// doesn't compile 
template< T (*f)(S) > // non-type template param, it's a function ptr 
struct Wrapper 
{ 
    static void wrapped(int x) 
    { 
    // do a bunch of other stuff here 
    f(static_cast<S>(x)); // call wrapped function, ignore result 

    } 
} 

然後我想這樣做:

AddCallback(Wrapper<foobar>::wrapped); 

然而,問題是,我不能只是繼續和使用在Wrapper模板中的函數參數中有一個「S」,我必須首先列出它作爲參數:

template< class T, class S, T (*f)(S) > 
struct Wrapper 
// ... 

但是這意味着使用(Wrapper<void,float,foobar>::wrapped)會更痛苦,理想情況下我只想傳遞函數指針,並自動計算出參數的類型(以及返回類型)。要清楚,在包裝函數中,我需要引用函數指針的類型(所以我確實需要一些等價的S或T)。

有沒有辦法做到這一點?

+0

@damndirtyape:我想過你的問題,我想我已經做了類似的事情。不幸的是它涉及很多代碼。基本上,我的解決方案有一個重載operator()的基類,我有工廠函數,它構造了基於傳遞的函數類型的基類。如果你喜歡,我可以在某處貼上代碼。 – 2009-07-15 19:28:23

回答

0

如果使用返回「包裝」的函數而不是直接引用它,編譯器將嘗試自動匹配函數調用的模板參數。

編輯:這個怎麼樣?

int foobar(float x); // wrappee 

template <typename T, typename S> 
struct Wrapper { 
    typedef T (*F)(S); 
    F f; 

    Wrapper(F f) : f(f) { } 

    void wrapped(S x) { 
     // do a bunch of other stuff here 
     f(x); // call wrapped function, ignore result 
    } 
}; 

template <typename T, typename S> 
Wrapper<T,S> getWrapper(T (*f)(S)) { 
    return Wrapper<T,S>(f); 
} 

... 
getWrapper(foobar).wrapped(7); 
+0

這並不能解決問題,因爲現在該函數的模板參數具有相同的問題。 – damndirtyape 2009-07-15 18:31:45

+0

你確定嗎?也許我只是不明白你在做什麼... – 2009-07-15 18:46:44

+0

不工作,因爲你將函數從一個靜態方法改變爲一個實例方法,但是整個過程是讓包裝的函數符合現有的回調簽名(這意味着它必須是靜態的)。 – damndirtyape 2009-07-15 18:51:38

0

編輯:完全新的答案

OK,我已經完全重新思考這個問題,並相信我得到你想要的。我之前已經做到了這一點:-P。

這裏的想法,我有一個基類,它重載operator(),然後我有一個子類的每個「arity」的功能。最後我有一個工廠函數,它將返回這些東西之一。代碼很大(可能有點矯枉過正),但效果很好。大部分的library_function重載都支持不同的語法,大多是不必要的。它也支持boost::bind函數,成員函數等等,比你可能需要的要多得多。

http://pastebin.com/m35af190

例,用法:

// map of library functions which will return an int. 
std::map<std::string, LibraryFunction<int> > functions; 

// function to register stuff in the map 
void registerFunction(const std::string &name, LibraryFunction<int> func) { 
    functions.insert(std::make_pair(name, func)); 
} 

後,你可以這樣做:

// the this param is so the function has access to the scripting engine and can pop off the parameters, you can easily chop it out 

// register 2 functions, one with no params, one with 1 param 
registerFunction("my_function", library_function1(*this, call_my_function)); 
registerFunction("my_function2", library_function0(*this, call_my_function2)); 

functions["my_function"](); 
functions["my_function2"](); 
0

我想看看提振。在第一次閱讀你的問題時,在我看來,<boost/function_types/parameter_types.hpp>提供了你的需求。

5

您可能希望考慮的一件事是使用LLVM或類似方法在運行時生成適當的蹦牀功能。或者這裏有一個靜態解決方案:

#include <iostream> 

void f(float f) { std::cout << f << std::endl; } 

template<typename T, typename S> struct static_function_adapter { 
     template<T(*f)(S)> struct adapt_container { 
       static void callback(int v) { 
         f(static_cast<S>(v)); 
       } 
     }; 

     template<T(*f)(S)> adapt_container<f> adapt() const { 
       return adapt_container<f>(); 
     } 
}; 

template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) { 
     return static_function_adapter<T, S>(); 
} 

#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback) 

int main() { 
     void (*adapted)(int) = ADAPTED_FUNCTION(f); 
     adapted(42); 
     return 0; 
} 

get_adapter函數允許我們推斷參數和返回類型; adapt()然後將其轉換成實際函數參數化的類型,最後我們在回調中獲得一個靜態函數。