具有可变参数模板的成员函数指针
member function pointer with variadic templates
我正在尝试用 C++ 编写 "manages" 委托的 class。我已经为我实现了委托 class。我希望这个委托管理器 class 有两个功能:
一个人会使用一个指向具有给定 input-argument/return 类型的特定类型的委托实例的指针,并将其缓存。
另一个函数将采用正确类型的成员函数,以便将缓存的委托实例绑定到它。
目前,我有:
template<typename... Args>
struct FunctionParamsPack { };
这是此函数采用的参数类型的容器。即对于 foo(int i, double d)
将是 int
和 double
。我遵循 here.
的建议
然后我有 DelegateInfoPack
class:
template<typename FuncRetType,typename... FuncParams>
struct DelegateInfoPack{
//for look-up by components in the program
typedef typename DelegateClass<FuncRetType, FuncParams...> _Delegate;
//for the delegate manager
typedef typename FuncRetType _FuncRetType;
typedef typename FunctionParamsPack<FuncParams...> _FuncParams;
};
程序中的组件包含此结构,它定义了三个类型名称,其中两个将在 DelegateManger 中使用 class:
template<typename DelegateInfoPack>
class DelegateManager
{
typedef typename DelegateInfoPack::_Delegate _Delegate;
typedef typename DelegateInfoPack::_FuncRetType _FuncRetType;
typedef typename DelegateInfoPack::_FuncParams _FuncParams;
void CacheDelegate(_Delegate* del,...) {}
template<typename UserClass>
void BindDelegate(..., _FuncRetType(UserClass::*fp)( _FuncParams())) {} //Doesn't work!
}
我的问题是 BindDelegate()
函数。我无法为具有给定 return 类型和输入参数类型的类型的成员函数创建正确的签名。
基本上,我需要知道如何使用给定的 return 类型和参数类型来获得正确的函数指针类型,以便我的 BindDelegate 将其作为参数。
一种方法是使用偏特化:
template<typename> class DelegateManager;
template<typename FuncRetType,typename... FuncParams>
class DelegateManager<DelegateInfoPack<FuncRetType,FuncParams...>>
{
template<typename UserClass>
void BindDelegate(_FuncRetType(UserClass::*fp)(FuncParams...))
{
}
};
另一种方法是使用 class 生成适当的函数类型
template <typename FuncRetType,typename FuncParams>
struct FunctionPointer;
template <typename FuncRetType,typename...ARGS>
struct FunctionPointer<FuncRetType,FunctionParamsPack<ARGS...>> {
typedef FuncRetType (Type)(ARGS...);
};
然后在您的 BindDelegate 成员函数中使用它:
template<typename UserClass>
void
BindDelegate(
typename FunctionPointer<_FuncRetType,_FuncParams>::Type UserClass::*fp
)
{ ... }
或者甚至可以将其放入您的 DelegateInfoPack class:
template<typename FuncRetType,typename... FuncParams>
struct DelegateInfoPack {
.
.
.
typedef FuncRetType (_FuncType)(FuncParams...);
};
并在您的 DelegateManager 中使用它
template<typename DelegateInfoPack>
struct DelegateManager
{
.
.
.
typedef typename DelegateInfoPack::_FuncType _FuncType;
template<typename UserClass>
void BindDelegate(_FuncType UserClass::*fp)
{
}
};
作为解决您的任务的另一种方法 - C++11 引入了新的语言功能,可以使您的代码更灵活地使用标准元素
#include <iostream>
#include <functional>
#include <tuple>
#include <iostream>
using std::cout;
using std::endl;
using namespace std::placeholders;
// helpers for tuple unrolling
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
// simple function
double foo_fn(int x, float y, double z)
{
return x + y + z;
}
// structure with memner function to call
struct foo_struct
{
// member function to be used as a delegate
double foo_fn(int x, float y, double z)
{
return x + y + z;
}
// this member function has different signature - but it can be used too
// please note that argument order is changed too
double foo_fn_4(int x, double z, float y, long xx)
{
return x + y + z + xx;
}
};
// delegate class that holds as delegate as its params for future call
template <typename Ret, typename ...Args>
struct delayed_call
{
// tuple can be used as FunctionParamsPack type
typedef std::tuple<Args...> params_type;
// std::function as delegate type
typedef std::function<Ret(Args...)> function_type;
// stored parameters
params_type params;
// stored delegate
function_type func;
// invocation
Ret operator()()
{
return callFunc(typename gens<sizeof...(Args)>::type());
}
// direct invocation
Ret operator()(Args... args)
{
return func(args...);
}
// internal invocation with tuple unrolling
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
};
int main(void)
{
// arguments
std::tuple<int, float, double> t = std::make_tuple(1, 5, 10);
// var #1 - you can use simple function as delegate
delayed_call<double, int,float, double> saved_foo_fn{t, foo_fn};
foo_struct fs;
// var #2 - you can use member function as delegate
delayed_call<double, int,float, double> saved_foo_fn_struct{t, std::bind(&foo_struct::foo_fn, fs, _1, _2, _3)};
// var #3 - you can use member function with different signature as delegate.
// bind 0 to xx and change argument order
delayed_call<double, int,float, double> saved_foo_fn_struct_4{t, std::bind(&foo_struct::foo_fn_4, fs, _1, _3, _2, 0l)};
// var #4 - you can use lambda function as delegate
delayed_call<double, int,float, double> saved_lambda{t, [](int x, float y, double z)
{
return x + y + z;
}
};
cout << "saved_foo_fn: " << saved_foo_fn() << endl;
cout << "saved_foo_fn_struct: " << saved_foo_fn_struct() << endl;
cout << "saved_foo_fn_struct_4: " << saved_foo_fn_struct_4() << endl;
cout << "saved_lambda: " << saved_lambda() << endl;
cout << "direct call with (1,2,3) to a member: " << saved_foo_fn_struct(1, 2, 3) << endl;
}
输出:
saved_foo_fn: 16
saved_foo_fn_struct: 16
saved_foo_fn_struct_4: 16
saved_lambda: 16
direct call with (1,2,3) to a member: 6
因此您不仅限于成员函数,还可以使用任何可调用类型甚至具有不同的签名
如果placeholders::_1...你看起来很丑 - there is a solution
我正在尝试用 C++ 编写 "manages" 委托的 class。我已经为我实现了委托 class。我希望这个委托管理器 class 有两个功能:
一个人会使用一个指向具有给定 input-argument/return 类型的特定类型的委托实例的指针,并将其缓存。
另一个函数将采用正确类型的成员函数,以便将缓存的委托实例绑定到它。
目前,我有:
template<typename... Args>
struct FunctionParamsPack { };
这是此函数采用的参数类型的容器。即对于 foo(int i, double d)
将是 int
和 double
。我遵循 here.
然后我有 DelegateInfoPack
class:
template<typename FuncRetType,typename... FuncParams>
struct DelegateInfoPack{
//for look-up by components in the program
typedef typename DelegateClass<FuncRetType, FuncParams...> _Delegate;
//for the delegate manager
typedef typename FuncRetType _FuncRetType;
typedef typename FunctionParamsPack<FuncParams...> _FuncParams;
};
程序中的组件包含此结构,它定义了三个类型名称,其中两个将在 DelegateManger 中使用 class:
template<typename DelegateInfoPack>
class DelegateManager
{
typedef typename DelegateInfoPack::_Delegate _Delegate;
typedef typename DelegateInfoPack::_FuncRetType _FuncRetType;
typedef typename DelegateInfoPack::_FuncParams _FuncParams;
void CacheDelegate(_Delegate* del,...) {}
template<typename UserClass>
void BindDelegate(..., _FuncRetType(UserClass::*fp)( _FuncParams())) {} //Doesn't work!
}
我的问题是 BindDelegate()
函数。我无法为具有给定 return 类型和输入参数类型的类型的成员函数创建正确的签名。
基本上,我需要知道如何使用给定的 return 类型和参数类型来获得正确的函数指针类型,以便我的 BindDelegate 将其作为参数。
一种方法是使用偏特化:
template<typename> class DelegateManager;
template<typename FuncRetType,typename... FuncParams>
class DelegateManager<DelegateInfoPack<FuncRetType,FuncParams...>>
{
template<typename UserClass>
void BindDelegate(_FuncRetType(UserClass::*fp)(FuncParams...))
{
}
};
另一种方法是使用 class 生成适当的函数类型
template <typename FuncRetType,typename FuncParams>
struct FunctionPointer;
template <typename FuncRetType,typename...ARGS>
struct FunctionPointer<FuncRetType,FunctionParamsPack<ARGS...>> {
typedef FuncRetType (Type)(ARGS...);
};
然后在您的 BindDelegate 成员函数中使用它:
template<typename UserClass>
void
BindDelegate(
typename FunctionPointer<_FuncRetType,_FuncParams>::Type UserClass::*fp
)
{ ... }
或者甚至可以将其放入您的 DelegateInfoPack class:
template<typename FuncRetType,typename... FuncParams>
struct DelegateInfoPack {
.
.
.
typedef FuncRetType (_FuncType)(FuncParams...);
};
并在您的 DelegateManager 中使用它
template<typename DelegateInfoPack>
struct DelegateManager
{
.
.
.
typedef typename DelegateInfoPack::_FuncType _FuncType;
template<typename UserClass>
void BindDelegate(_FuncType UserClass::*fp)
{
}
};
作为解决您的任务的另一种方法 - C++11 引入了新的语言功能,可以使您的代码更灵活地使用标准元素
#include <iostream>
#include <functional>
#include <tuple>
#include <iostream>
using std::cout;
using std::endl;
using namespace std::placeholders;
// helpers for tuple unrolling
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
// simple function
double foo_fn(int x, float y, double z)
{
return x + y + z;
}
// structure with memner function to call
struct foo_struct
{
// member function to be used as a delegate
double foo_fn(int x, float y, double z)
{
return x + y + z;
}
// this member function has different signature - but it can be used too
// please note that argument order is changed too
double foo_fn_4(int x, double z, float y, long xx)
{
return x + y + z + xx;
}
};
// delegate class that holds as delegate as its params for future call
template <typename Ret, typename ...Args>
struct delayed_call
{
// tuple can be used as FunctionParamsPack type
typedef std::tuple<Args...> params_type;
// std::function as delegate type
typedef std::function<Ret(Args...)> function_type;
// stored parameters
params_type params;
// stored delegate
function_type func;
// invocation
Ret operator()()
{
return callFunc(typename gens<sizeof...(Args)>::type());
}
// direct invocation
Ret operator()(Args... args)
{
return func(args...);
}
// internal invocation with tuple unrolling
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
};
int main(void)
{
// arguments
std::tuple<int, float, double> t = std::make_tuple(1, 5, 10);
// var #1 - you can use simple function as delegate
delayed_call<double, int,float, double> saved_foo_fn{t, foo_fn};
foo_struct fs;
// var #2 - you can use member function as delegate
delayed_call<double, int,float, double> saved_foo_fn_struct{t, std::bind(&foo_struct::foo_fn, fs, _1, _2, _3)};
// var #3 - you can use member function with different signature as delegate.
// bind 0 to xx and change argument order
delayed_call<double, int,float, double> saved_foo_fn_struct_4{t, std::bind(&foo_struct::foo_fn_4, fs, _1, _3, _2, 0l)};
// var #4 - you can use lambda function as delegate
delayed_call<double, int,float, double> saved_lambda{t, [](int x, float y, double z)
{
return x + y + z;
}
};
cout << "saved_foo_fn: " << saved_foo_fn() << endl;
cout << "saved_foo_fn_struct: " << saved_foo_fn_struct() << endl;
cout << "saved_foo_fn_struct_4: " << saved_foo_fn_struct_4() << endl;
cout << "saved_lambda: " << saved_lambda() << endl;
cout << "direct call with (1,2,3) to a member: " << saved_foo_fn_struct(1, 2, 3) << endl;
}
输出:
saved_foo_fn: 16
saved_foo_fn_struct: 16
saved_foo_fn_struct_4: 16
saved_lambda: 16
direct call with (1,2,3) to a member: 6
因此您不仅限于成员函数,还可以使用任何可调用类型甚至具有不同的签名
如果placeholders::_1...你看起来很丑 - there is a solution