有没有办法获取可调用对象的参数列表,然后将其用作模板中的参数包?
is there any way to obtain the callable's argument list and then use it as parameter pack in template?
callable 应该是任何函数指针,std::function 或 lambda。我想获取它们的参数列表并将它们用作参数包:
template <typename callable_T>
class callback2_t
{
public:
using callable_t = callable_T;
using ret_T = some_magic<callable_T>::ret_t;
using data_T = the_first_type<argTs>;
...
static ret_T _callback(some_magic<callable_T>::argTs... args);
};
目的是简化跟随模板,使其适用于所有类型的可调用对象而无需创建别名:
// other library only accept function pointer as callback, I want to wrap it to remove the callback when data go out of scope.
template <typename callable_T, typename ret_T, typename data_T, typename ...arg_Ts>
class callback_t
{
using callable_t = callable_T;
public:
callback_t(const char* signal, callable_t callable, data_T data)
: f_{std::move(callable)}, data_{std::move(data)}
{
std::cout << signal << " " << typeid(callable).name() << std::endl;
//register_callback(signal, _callback, this);
}
~callback_t()
{
//unregister_callback(signal);
}
void test_callback(arg_Ts... args)
{
_callback(args..., this);
}
private:
callable_t f_;
data_T data_;
static ret_T _callback(arg_Ts... args, callback_t * self)
{
return self->f_(&self->data_, args...);
}
};
// I donot want convert function pointer to std::function
// if possible. std::function is a heavy class.
template <typename ret_T, typename data_T, typename ...arg_Ts>
using fp_callback_t = callback_t<ret_T(*)(void *, arg_Ts...), ret_T, data_T, arg_Ts...>;
template <typename ret_T, typename data_T, typename ...arg_Ts>
using func_callback_t = callback_t<std::function<ret_T(void *, arg_Ts...)>, ret_T, data_T, arg_Ts...>;
我们可以这样使用模板:
struct A{float x;};
struct B{int x;};
struct C{uint x;};
int func1(void * data, A* a)
{
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << std::endl;
return a->x + c->x;
}
void func2(void *data, B* b, C* c)
{
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << std::endl;
}
int main()
{
A a1{-10.5f};
B b1 {5};
C c1{300};
auto callback1 = fp_callback_t<int, C, A*>("signal1", &func1, c1);
callback1.test_callback(&a1);
auto callback2 = fp_callback_t<void, A, B*, C*>("signal2", &func2, a1);
callback2.test_callback(&b1, &c1);
std::function<int(void*, A*)> fc1 = [=](void* data, A* a){
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << ", " << a1.x << std::endl;
return (int)a1.x;
};
std::function<void(void*, B*, C*)> fc2 = [=](void* data, B* b, C* c){
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << ", " << c1.x << std::endl;
};
auto callback3 = func_callback_t<int, C, A*>("signal3", fc1, c1);
callback3.test_callback(&a1);
auto callback4 = func_callback_t<void, A, B*, C*>("signal4", fc2, a1);
callback4.test_callback(&b1, &c1);
return 0;
}
输出是:
signal1 PFiPvP1AE
-10.5, 300
signal2 PFvPvP1BP1CE
5, 300, -10.5
signal3 NSt3__18functionIFiPvP1AEEE
-10.5, 300, -10.5
signal4 NSt3__18functionIFvPvP1BP1CEEE
5, 300, -10.5, 300
推导应该在没有明确专门化模板参数的情况下工作;我想避免别名;它应该与函数指针、std::function 和 lambda 一起工作; callable_t 应该是给定的,而不是将它们全部转换为 std::function。如下所示:
auto callback1 = callback2_t("signal1", &func1, c1);
callback1.test_callback(&a1);
auto callback2 = callback2_t("signal2", &func2, a1);
callback2.test_callback(&b1, &c1);
std::function<int(void*, A*)> fc1 = [=](void* data, A* a){
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << ", " << a1.x << std::endl;
return (int)a1.x;
};
auto callback3 = callback2_t("signal3", fc1, c1);
callback3.test_callback(&a1);
auto lambda1 = [=](void* data, B* b, C* c){
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << ", " << c1.x << std::endl;
};
auto callback4 = callback2_t("signal4", lambda1, a1);
callback4.test_callback(&b1, &c1);
这是一个有趣的测验 =) 诀窍是将指针传递给 lambda::operator()
并让类型推导起作用:
template <typename Ret, typename ... Args>
struct Callback {
Callback() {
std::cout << "Created " << typeid(*this).name() << "\n";
}
};
template <typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback(std::function<Ret (Args...)> const &fn) {
std::cout << "Function!\n";
return Callback<Ret, Args...>();
}
template <typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback(Ret (*fn)(Args...)) {
std::cout << "Function pointer!\n";
return Callback<Ret, Args...>();
}
template <typename Lambda, typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback_lambda(Lambda const &, Ret (Lambda::*)(Args...) const) {
std::cout << "Lambda!\n";
return Callback<Ret, Args...>();
}
template <typename Callable>
auto create_callback(Callable const &c) {
return create_callback_lambda(c, &Callable::operator());
}
你根本不需要推导参数。只需让模板吸收它们并将它们转发给可调用对象即可。
template <typename callable_T, typename data_T>
class callback_t
{
using callable_t = callable_T;
public:
callback_t(const char* signal, callable_t callable, data_T data)
: f_{std::move(callable)}, data_{std::move(data)}
{
}
template<typename...arg_Ts>
auto test_callback(arg_Ts... args)
{
return _callback(this, args...);
}
private:
callable_t f_;
data_T data_;
template<typename...arg_Ts>
static auto _callback(callback_t * self, arg_Ts... args)
{
return self->f_(&self->data_, args...);
}
};
即使 operator()
过载也能正常工作:
int test()
{
callback_t cc("test", [](auto x, auto y){ return *x + y;}, 42);
return cc.test_callback(9); // returns 42 + 9 = 51
}
callable 应该是任何函数指针,std::function 或 lambda。我想获取它们的参数列表并将它们用作参数包:
template <typename callable_T>
class callback2_t
{
public:
using callable_t = callable_T;
using ret_T = some_magic<callable_T>::ret_t;
using data_T = the_first_type<argTs>;
...
static ret_T _callback(some_magic<callable_T>::argTs... args);
};
目的是简化跟随模板,使其适用于所有类型的可调用对象而无需创建别名:
// other library only accept function pointer as callback, I want to wrap it to remove the callback when data go out of scope.
template <typename callable_T, typename ret_T, typename data_T, typename ...arg_Ts>
class callback_t
{
using callable_t = callable_T;
public:
callback_t(const char* signal, callable_t callable, data_T data)
: f_{std::move(callable)}, data_{std::move(data)}
{
std::cout << signal << " " << typeid(callable).name() << std::endl;
//register_callback(signal, _callback, this);
}
~callback_t()
{
//unregister_callback(signal);
}
void test_callback(arg_Ts... args)
{
_callback(args..., this);
}
private:
callable_t f_;
data_T data_;
static ret_T _callback(arg_Ts... args, callback_t * self)
{
return self->f_(&self->data_, args...);
}
};
// I donot want convert function pointer to std::function
// if possible. std::function is a heavy class.
template <typename ret_T, typename data_T, typename ...arg_Ts>
using fp_callback_t = callback_t<ret_T(*)(void *, arg_Ts...), ret_T, data_T, arg_Ts...>;
template <typename ret_T, typename data_T, typename ...arg_Ts>
using func_callback_t = callback_t<std::function<ret_T(void *, arg_Ts...)>, ret_T, data_T, arg_Ts...>;
我们可以这样使用模板:
struct A{float x;};
struct B{int x;};
struct C{uint x;};
int func1(void * data, A* a)
{
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << std::endl;
return a->x + c->x;
}
void func2(void *data, B* b, C* c)
{
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << std::endl;
}
int main()
{
A a1{-10.5f};
B b1 {5};
C c1{300};
auto callback1 = fp_callback_t<int, C, A*>("signal1", &func1, c1);
callback1.test_callback(&a1);
auto callback2 = fp_callback_t<void, A, B*, C*>("signal2", &func2, a1);
callback2.test_callback(&b1, &c1);
std::function<int(void*, A*)> fc1 = [=](void* data, A* a){
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << ", " << a1.x << std::endl;
return (int)a1.x;
};
std::function<void(void*, B*, C*)> fc2 = [=](void* data, B* b, C* c){
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << ", " << c1.x << std::endl;
};
auto callback3 = func_callback_t<int, C, A*>("signal3", fc1, c1);
callback3.test_callback(&a1);
auto callback4 = func_callback_t<void, A, B*, C*>("signal4", fc2, a1);
callback4.test_callback(&b1, &c1);
return 0;
}
输出是:
signal1 PFiPvP1AE
-10.5, 300
signal2 PFvPvP1BP1CE
5, 300, -10.5
signal3 NSt3__18functionIFiPvP1AEEE
-10.5, 300, -10.5
signal4 NSt3__18functionIFvPvP1BP1CEEE
5, 300, -10.5, 300
推导应该在没有明确专门化模板参数的情况下工作;我想避免别名;它应该与函数指针、std::function 和 lambda 一起工作; callable_t 应该是给定的,而不是将它们全部转换为 std::function。如下所示:
auto callback1 = callback2_t("signal1", &func1, c1);
callback1.test_callback(&a1);
auto callback2 = callback2_t("signal2", &func2, a1);
callback2.test_callback(&b1, &c1);
std::function<int(void*, A*)> fc1 = [=](void* data, A* a){
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << ", " << a1.x << std::endl;
return (int)a1.x;
};
auto callback3 = callback2_t("signal3", fc1, c1);
callback3.test_callback(&a1);
auto lambda1 = [=](void* data, B* b, C* c){
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << ", " << c1.x << std::endl;
};
auto callback4 = callback2_t("signal4", lambda1, a1);
callback4.test_callback(&b1, &c1);
这是一个有趣的测验 =) 诀窍是将指针传递给 lambda::operator()
并让类型推导起作用:
template <typename Ret, typename ... Args>
struct Callback {
Callback() {
std::cout << "Created " << typeid(*this).name() << "\n";
}
};
template <typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback(std::function<Ret (Args...)> const &fn) {
std::cout << "Function!\n";
return Callback<Ret, Args...>();
}
template <typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback(Ret (*fn)(Args...)) {
std::cout << "Function pointer!\n";
return Callback<Ret, Args...>();
}
template <typename Lambda, typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback_lambda(Lambda const &, Ret (Lambda::*)(Args...) const) {
std::cout << "Lambda!\n";
return Callback<Ret, Args...>();
}
template <typename Callable>
auto create_callback(Callable const &c) {
return create_callback_lambda(c, &Callable::operator());
}
你根本不需要推导参数。只需让模板吸收它们并将它们转发给可调用对象即可。
template <typename callable_T, typename data_T>
class callback_t
{
using callable_t = callable_T;
public:
callback_t(const char* signal, callable_t callable, data_T data)
: f_{std::move(callable)}, data_{std::move(data)}
{
}
template<typename...arg_Ts>
auto test_callback(arg_Ts... args)
{
return _callback(this, args...);
}
private:
callable_t f_;
data_T data_;
template<typename...arg_Ts>
static auto _callback(callback_t * self, arg_Ts... args)
{
return self->f_(&self->data_, args...);
}
};
即使 operator()
过载也能正常工作:
int test()
{
callback_t cc("test", [](auto x, auto y){ return *x + y;}, 42);
return cc.test_callback(9); // returns 42 + 9 = 51
}