template<class T>using type=T; // makes some declarations easier
template<class F>
struct callback_t;
template<class F, class Sig>
struct cast_helper_pvoid_last;
template<class F, class R, class... Args>
struct cast_helper_pvoid_last<F, R(Args...)> {
type<R(*)(Args..., void*)> operator()() const {
return [](Args... args, void* pvoid)->R {
auto* callback = static_cast<callback_t<F>*>(pvoid);
return callback->f( std::forward<Args>(args)... );
};
}
};
template<class F>
struct callback_t {
F f;
void* pvoid() { return this; }
template<class Sig>
auto pvoid_at_end()->decltype( cast_helper_pvoid_last<F, Sig>{}() ) {
return cast_helper_pvoid_last<F,Sig>{}();
}
};
template<class T>using decay_t=typename std::decay<T>::type;
template<class F>
callback_t<decay_t<F>> make_callback( F&& f ) { return {std::forward<F>(f)}; }
使用示例:
int x = 3;
auto callback = make_callback( [&]( int y ) { return x+y; } );
int (*func)(int, void*) = callback.pvoid_at_end<int(int)>();
std::cout << func( 1, callback.pvoid() ) << "\n";
should print 4. (live example)
callback_t 的生命周期必须超过它产生的 pvoid。
我可以自动推断函数指针的签名,而不是要求您传递<int(int)>(没有void* 的签名),但这又使代码更容易。
如果您希望 void* 排在第一位,请添加以下内容:
template<class F, class Sig>
struct cast_helper_pvoid_first;
template<class F, class R, class... Args>
struct cast_helper_pvoid_first<class F, R(Args...)> {
type<R(*)(void*, Args...)> operator()() const {
return [](void* pvoid, Args... args)->R {
auto* callback = static_cast<callback<F>*>(pvoid);
return callback->f( std::forward<Args>(args)... );
};
}
};
// inside the callback_t<?> template:
template<class Sig>
auto pvoid_at_start()->decltype( cast_helper_pvoid_first<F, Sig>{}() ) {
return cast_helper_pvoid_first<F,Sig>{}();
}
在中间使用void* 会比较棘手。
如果你有调用约定问题,那么我们需要使用辅助对象
让pvoid_at_end 返回一个cast_helper_pvoid_last 而不是调用()。
然后,将operator 重载添加到您需要支持的每个调用约定的强制转换函数指针。主体与operator() 相同,因为 lambda 应该支持其中任何一个。
或者,通过一些 C++14 支持,您可以将 operator() 的返回类型更改为 auto,否则代码保持不变,并依靠直接 cast-from-lambda 来获得正确的调用约定。