我正在用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&amp;),但这是一个令人遗憾的解决方案,因为我必须创建另一个singleArgCallbackAcceptingReference类,接受具有以下签名的函数指针:
void (*callbackMethod)(T& arg);
因此,我的代码重复了2 ^ n次,其中n是回调函数的参数个数。
有人知道任何解决方法或有任何想法如何修复它?提前谢谢!
答案 0 :(得分:3)
问题在于make_callback()
,T
变为const std::string&
,而T
中的singleArgumentCallback
变为U
。但是,const char*
是std::string
,因此会创建一个临时singleArgumentCallback
对象并绑定到make_callback()
中的该引用。当singleArgumentCallback
完成时,该临时文件将被销毁,从而使创建的make_callback()
对象具有对不再存在的对象的引用。
您需要做的是首先从传递到template< typename T > struct remove_ref { typedef T result_type; };
template< typename T > struct remove_ref<T&> { typedef T result_type; };
的类型中删除引用(以及可能的cv限定符)。作为Marcelo suggested,Boost.TypeTraits可以帮助您完成此操作,但如果您愿意,可以自行烹饪:
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);
}
更改为:
{{1}}
答案 1 :(得分:0)
Boost.TypeTraits可能有所帮助。 add_reference将具体类型转换为引用类型,同时保留引用类型。
答案 2 :(得分: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);
}
如果有人看到任何可能的改进,我会很乐意学习!
谢谢大家, 卡罗尔