2010-03-27 95 views
2

我在C++中編寫了一些回調實現。C++無效參考問題

我有一個抽象的回調類,讓我們說:

/** Abstract callback class. */ 
class callback { 
public: 

    /** Executes the callback. */ 
    void call() { do_call(); }; 
protected: 

    /** Callback call implementation specific to derived callback. */ 
    virtual void do_call() = 0; 
}; 

每個回調創建(接受單參數的函數,雙參數的函數...)創建爲使用下面的一個一個mixin :

/** Makes the callback a single-argument callback. */ 
template <typename T> 
class singleArgumentCallback { 
protected: 
    /** Callback argument. */ 
    T arg; 

public: 
    /** Constructor. */ 
    singleArgumentCallback(T arg): arg(arg) { } 
}; 

/** Makes the callback a double-argument callback. */ 
template <typename T, typename V> 
class doubleArgumentCallback { 
protected: 
    /** Callback argument 1. */ 
    T arg1; 

    /** Callback argument 2. */ 
    V arg2; 

public: 
    /** Constructor. */ 
    doubleArgumentCallback(T arg1, V arg2): arg1(arg1), arg2(arg2) { } 
}; 

例如,單ARG回調函數應該是這樣的:

/** Single-arg callbacks. */ 
template <typename T> 
class singleArgFunctionCallback: 
    public callback, 
    protected singleArgumentCallback<T> { 

    /** Callback. */ 
    void (*callbackMethod)(T arg); 

public: 
    /** Constructor. */ 
    singleArgFunctionCallback(void (*callback)(T), T argument): 
     singleArgumentCallback<T>(argument), 
     callbackMethod(callback) { } 

protected: 
    void do_call() { 
     this->callbackMethod(this->arg); 
    } 
}; 

爲了方便用戶,我想有一個,而無需用戶考慮的細節創建一個回調的方法,這樣一方面可以撥打電話(這個接口是不受改變,不幸):

void test3(float x) { std::cout << x << std::endl; } 
void test5(const std::string& s) { std::cout << s << std::endl; } 

make_callback(&test3, 12.0f)->call(); 
make_callback(&test5, "oh hai!")->call(); 

我目前執行的make_callback(...)如下:

/** Creates a callback object. */ 
template <typename T, typename U> callback* make_callback(
    void (*callbackMethod)(T), U argument) { 
    return new singleArgFunctionCallback<T>(callbackMethod, argument); 
} 

不幸的是,當我打電話make_callback(&test5, "oh hai!")->call();我得到在標準輸出一個空字符串。我相信問題是在回調初始化後引用超出了範圍。

我試過使用指針和引用,但它不可能有指針/引用引用,所以我失敗了。我唯一的解決方案是禁止將引用類型替換爲T(例如,T不能是std :: string &),但這是一個令人傷心的解決方案,因爲我必須創建另一個接受具有以下簽名的函數指針的singleArgCallbackAcceptingReference類:

void (*callbackMethod)(T& arg); 

因此,我的代碼被重複2^n次,其中n是回調函數的參數個數。

有沒有人知道任何解決方法或有任何想法如何解決它?提前致謝!

+1

「我嘗試使用指針和引用,但它不可能有一個指針/參考參考」:'INT一個= 1; int&a_ref = a; int * p_a_ref = &a_ref;(* p_a_ref)= 2;' – mlvljr 2010-03-27 08:29:25

+0

@mlvljr:這是否是一個指向引用的指針?不是。指針指向'a'。你根本無法指出參考。 – GManNickG 2010-03-27 15:21:51

+0

@GMan「這是否假設[d]是指向參考的指針?」 - 當然不是,它只是顯示如何[很容易]得到一個指向某個東西的指針,以及引用(OP可能願意但不知道的東西)引用的東西,也就是另一個(本例中的第二個)間接的程度,沒有別的。 – mlvljr 2010-03-28 07:29:37

回答

3

的問題是,在make_callback()T變得const std::string&,這反過來又成爲您的singleArgumentCallbackTU,但是,是const char*,因此創建一個臨時std::string對象並綁定到singleArgumentCallback中的該引用。當make_callback()完成時,該臨時被破壞,將創建的singleArgumentCallback對象引用到不再存在的對象。

你將不得不做的是首先從傳入make_callback()的類型中刪除引用(也可能是cv限定符)。作爲Marcelo suggestedBoost.TypeTraits可以幫你做到這一點,但如果你想,這是不難煮了你自己的東西:

template< typename T > struct remove_ref  { typedef T result_type; }; 
template< typename T > struct remove_ref<T&> { typedef T result_type; }; 

然後換make_callback()到:

template <typename T, typename U> 
callback* make_callback(void (*callbackMethod)(T), U argument) 
{ 
    typedef typename remove_ref<T>::result_type arg_type; 
    return new singleArgFunctionCallback<arg_type>(callbackMethod, argument); 
} 
+0

太好了,謝謝你的提示!它沒有開箱即用,但是在一些......我們說,'修復'後,我明白了。完整的解決方案發布如下。 不幸的是,我不允許使用Boost。但是,謝謝,我將在未來記住這一點! – Karol 2010-03-28 12:09:58

0

感謝SBI,我得到這個東西:-)

我結束了該解決方案的工作是在這裏:

template <typename T> struct removeRef  { typedef T resultType; }; 
template <typename T> struct removeRef<T&> { typedef T resultType; }; 

/** Single-arg callbacks. */ 
template <typename T, typename U> 
class singleArgFunctionCallback: 
    public callback, 
    protected singleArgumentCallback<U> { 

    /** Callback. */ 
    void (*callbackMethod)(T arg); 

public: 
    /** Constructor. */ 
    singleArgFunctionCallback(void (*callback)(T), U argument): 
     singleArgumentCallback<U>(argument), 
     callbackMethod(callback) { } 

protected: 
    void do_call() { 
     this->callbackMethod(this->arg); 
    } 
}; 

template <typename T, typename U> 
callback* make_callback(void (*callbackMethod)(T), U argument) { 
    typedef T ArgumentType; 
    typedef typename removeRef<T>::resultType StrippedArgumentType; 
    return new singleArgFunctionCallback<ArgumentType, StrippedArgumentType>(callbackMethod, argument); 
} 

如果有人看到任何可能的改進,我很樂意學習!

感謝所有, 卡羅爾