2010-03-20 11 views
5

Extends通用回調

Related

所以,我努力學習模板元編程更好,我想這是一個很好的鍛鍊吧。

我試着寫代碼,可以回調函數與任意數量的我喜歡傳遞給它的參數。

 
// First function to call 
int add(int x, int y) ; 

// Second function to call 
double square(double x) ; 

// Third func to call 
void go() ; 

回調創建的代碼應該是這樣的:

 
// Write a callback object that 
// will be executed after 42ms for "add" 
Callback<int, int, int> c1 ; 
c1.func = add ; 
c1.args.push_back(2); // these are the 2 args 
c1.args.push_back(5); // to pass to the "add" function 
         // when it is called 

Callback<double, double> c2 ; 
c2.func = square ; 
c2.args.push_back(52.2) ; 

我在想什麼,使用模板元編程我希望能夠宣佈像回調,寫這樣一個結構(請記住,這是非常僞代碼)

 
<TEMPLATING ACTION <<ANY NUMBER OF TYPES GO HERE>> > 
struct Callback 
{ 
    double execTime ; // when to execute 
    TYPE1 (*func)(TYPE2 a, TYPE3 b) ; 

    void* argList ; // a stored list of arguments 
         // to plug in when it is time to call __func__ 
} ; 

因此,當與

呼籲
 
Callback<int, int, int> c1 ; 

您將自動獲得由< HARDCORE模板ACTION >像

 
struct Callback 
{ 
    double execTime ; // when to execute 
    int (*func)(int a, int b) ; 

    void* argList ; // this would still be void*, 
         // but I somehow need to remember 
         // the types of the args.. 
} ; 

在正確的方向的任何指針一個struct構建你上手就寫這個?

回答

1

boost::bind。我有更多一點的說......時間可能是最花鑽研它們的來源,並試圖重新實現它,如果你真的想了解的內部。但是,鑑於他們已經完善了它,重新實現只是一種學術追求。

2

您可以variadic templates,該編譯器可能不支持這樣做。我從來沒有用過它們,因此可能會弄錯一些細節,但我會盡力描述它們。

可變參數模板使用 「...」 運算符。在模板聲明(或其他類型的表達式),省略號表示形式參數可以採取任何數量的參數。

template <typename ... Args> 
class Variadic { 
public: 
    operator()(Args&& ... args); 
}; 

在函數調用表達式中,省略號將其左邊的參數解包。

Variadic<Args>::operator(Args&& ... args) { 
    func(args...); 
} 

要轉發,您可能需要使用std::forward;這是我的知識變得模糊的一個領域。把它放在一起,我們得到:

template <typename ReturnValue, typename ... Args> 
class Callback { 
    typedef ReturnValue (*Func)(Args ... args); 

    double execTime; 
    Func func; 
    Args... args; 

public: 
    Callback(double et, Func f) : execTime(et), func(f) {} 
    ReturnValue operator()(Args&& ... a); 
    ReturnValue operator()(); 
}; 

template <typename ReturnValue, typename ... Args> 
ReturnValue Callback<ReturnValue, Args>::operator()(Args&& ... a) { 
    return (*func)(std::forward(a)...); 
} 
template <typename ReturnValue, typename ... Args> 
ReturnValue Callback<ReturnValue, Args>::operator()() { 
    return operator(*func)(args...); 
} 
+1

變量模板是C++ 0x的一部分。一個支持它們的編譯器(或者甚至是一個支持更少C++ 0x的編譯器)也將包含C++ 0x函數對象和'std :: bind',它與'boost :: bind'相似,並且實現了你所要做的談論。 – Potatoswatter

0

C++ 0x添加可變模板,它直接支持一個模板,它接受任意數量的參數。如果沒有,你可以使用偏特來模擬它,但它需要的參數,每個號碼單獨的專業化。例如,你可以支持從1到3個參數是這樣的:

class null_class {}; 

template <class func, class arg1, class arg2, class arg3> 
class callback_t { 
    func f; 
    arg1 a; 
    arg2 b; 
    arg3 c; 
public: 
    callback_t(func f, arg1 a, arg2 b, arg3 c) : f(f), a(a), b(b), c(c) {} 
    double operator()() const { return f(a, b, c); } 
}; 

template <class func, class arg1, class arg2> 
class callback_t<func, arg1, arg2, null_class> { 
    func f; 
    arg1 a; 
    arg2 b; 
public: 
    callback_t(func f, arg1 a, arg2 b) : f(f), a(a), b(b) {} 
    double operator()() const { return f(a, b); } 
}; 

template <class func, class arg1> 
class callback_t<func, arg1, null_class, null_class> { 
    func f; 
    arg1 a; 
public: 
    callback_t(func f, arg1 a) : f(f), a(a) {} 
    double operator()() const { return f(a); } 
}; 

template <class func, class arg1, class arg2, class arg3> 
callback_t<func, arg1, arg2, arg3> 
callback(func f, arg1 a, arg2 b, arg3 c) { 
    return callback_t<func, arg1, arg2, arg3>(f, a, b, c); 
} 

template <class func, class arg1, class arg2> 
callback_t<func, arg1, arg2, null_class> 
callback(func f, arg1 a, arg2 b) { 
    return callback_t<func, arg1, arg2, null_class>(f, a, b); 
} 

template <class func, class arg> 
callback_t<func, arg, null_class, null_class> 
callback(func f, arg a) { 
    return callback_t<func, arg, null_class, null_class>(f, a); 
} 

#ifdef TEST 
#include <iostream> 

double square(double d) { 
    return d * d; 
} 

double add(double a, double b) { 
    return a + b; 
} 

double sum(double a, double b, double c) { 
    return a + b + c; 
} 

int main() { 
    double a = 2.0, b = 3.0, c=4.0; 

    double d = callback(square, a)(); 
    double e = callback(add, b, c)(); 
    double f = callback(sum, a, b, c)(); 

    std::cout << "2.0 squared = " << d << "\n"; 
    std::cout << "3.0 + 4.0 = " << e << "\n"; 
    std::cout << "Sum = " << f << "\n"; 
    return 0; 
} 

#endif 

返回類型可以和模板,但我已經離開了這一點爲簡單起見(或至少降低了複雜性)。

0

首先,你應該檢查出Boost.Function,因爲它是關於環繞功能自動,它會給你的想法,我認爲;)

其次,你的語法是有點尷尬。您可以完全使用函數簽名,一部分作爲模板參數,這很好地與可變參數模板的問題,因爲它允許你傳遞的類型任意數量的交易;)

Callback< int(int,int) > callback; 

會指示你的回調將採取指向與您的簽名類似的函數的指針addint add(int, int)。我更喜歡這種語法,因爲它使我們傳遞的內容更加清晰。

在我們開始之前,雖然我有一個問題:你想對返回類型做什麼?

1.參考

還有一些東西,像Boost.Fusion庫,可以幫助你很多(基本上,元組)。

此外,檢查出Boost.FunctionTypes它提供功能分析功能簽名的設施。

2.在路上再次

// It is nice to have a base class 
// Generally callbacks do not return anything though... 
struct CallbackBase 
{ 
    virtual ~CallbackBase(); 
    virtual void execute() const = 0; 
}; 

namespace func_ = boost::function_types; 

template < 
    class Parameters, 
    class N = typename mpl_::minus< 
    typename mpl_::size<Parameters>::type, 
    mpl_::size_t<1> 
    >::type 
> 
class Streamer 
{ 
public: 
    typedef Streamer< Parameters, typename mpl_::minus<N,1>::type > next_type; 
    typedef typename mpl_::size<Parameters>::type size_type; 
    typedef typename mpl_::minus< size_type, N >::type index_type; 
    typedef typename mpl_::at<Parameters, index_type>::type arg_type; 

    Streamer(Parameters& p): mParameters(p) {} 

    next_type operator<<(arg_type arg) 
    { 
    boost::fusion::at_c<index_type>(mParameters) = arg; 
    return next_type(mParameters); 
    } 

private: 
    Parameters& mParameters; 
}; 

template <class Parameters> 
struct Streamer<Paramaters,0> 
{ 
    Streamer(Parameters&) {} 
}; 


template <class Function> 
class Callback: public CallbackBase 
{ 
public: 
    typedef typename func_::result_type<Function>::type result_type; 
    typedef typename func_::parameters_type<Function>::type parameters_type; 
    typedef typename func_::function_pointer< 
    typename func_::components<Function>::type 
    >::type function_pointer; 

    Callback(function_pointer f): mFunction(f) {} 

    virtual void execute() const 
    { 
    mReturn = Invoke<function_pointer>::Do(f,mParameters); 
    } 

    Streamer<parameters_type> operator<<(typename mpl_::at<parameters_type, 0>::type arg) 
    { 
    boost::fusion::at_c<0>(mParameters) = arg; 
    return Streamer<parameters_type>(mParameters); 
    } 

private: 
    function_pointer f; 
    result_type mResult; 
    parameters_type mParameters; 
}; 

嗯,這就是我竟。我還沒有處理實際的調用,它需要解開元組來將參數傳遞給函數。

到目前爲止用法是:

int add(int,int); 

void pass(const CallbackBase& b); 

int main(int argc, char* argv[]) 
{ 
    Callback<int(int,int)> c(&add); 
    c << 2 << 4; 
    pass(c); 
} 

我強烈建議您鑽研Boost.Fusion,如果你想追求你的研究在這一領域,作爲純粹的模板元編程往往是徒勞的,如果你不能將結果帶入運行時環境:)