2010-03-27 91 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); 
} 

如果有人看到任何可能的改进,我很乐意学习!

感谢所有, 卡罗尔