我正在尝试为不同的函数实现一个容器类,我可以在其中保存函数指针,并在稍后调用这些函数.我会尽量解决我的问题更准确.
例如,我有2个不同的测试功能:
int func1(int a,int b) { printf("func1 works! %i %i\n",a,b); return 0; } void func2(double a,double b) { printf("func2 works! %.2lf %.2lf\n",b); }
而且我也有数组变量,它们包含函数参数:
std::vector<boost::variant<int,double>> args = {2.2,3.3};
我决定使用我自己的functor类派生自一些基类(我想到使用虚拟方法):
class BaseFunc { public: BaseFunc() {} ~BaseFunc() {} }; template <typename T> class Func; template <typename R,typename... Tn> class Func<R(Tn...)> : public BaseFunc { typedef R(*fptr_t)(Tn...); fptr_t fptr; public: Func() : fptr(nullptr) {} Func(fptr_t f) : fptr(f) {} R operator()(Tn... args) { return fptr(args...); } Func& operator=(fptr_t f) { fptr = f; return *this; } };
另外我决定存储一些关于函数及其参数的信息:
struct TypeInfo { int type_id; // for this example: 0 - int,1 - double template <class T> void ObtainType() { if (std::is_same<void,T>::value) type_id = 0; else if (std::is_same<int,T>::value) type_id = 1; else if (std::is_same<double,T>::value) type_id = 2; else type_id = -1; } }; struct FunctionInfo { public: FunctionInfo() {} FunctionInfo(BaseFunc *func,const TypeInfo& ret,std::vector<TypeInfo>& args) : func_ptr(func),return_info(ret) { args_info.swap(args); } ~FunctionInfo() { delete func_ptr; } BaseFunc * func_ptr; TypeInfo return_info; std::vector<TypeInfo> args_info; };
所以现在我可以定义一个容器类:
class Container { private: template <size_t n,typename... T> void ObtainTypeImpl(size_t i,TypeInfo& t) { if (i == n) t.ObtainType<std::tuple_element<n,std::tuple<T...>>::type>(); else if (n == sizeof...(T)-1) throw std::out_of_range("Tuple element out of range."); else ObtainTypeImpl<(n < sizeof...(T)-1 ? n + 1 : 0),T...>(i,t); } template <typename... T> void ObtainType(size_t i,TypeInfo& t) { return ObtainTypeImpl<0,t); } public: template <class R,class ...Args> void AddFunc(const std::string& str,R(*func)(Args...)) { BaseFunc * func_ptr = new Func<R(Args...)>(func); size_t arity = sizeof...(Args); TypeInfo ret; ret.ObtainType<R>(); std::vector<TypeInfo> args; args.resize(arity); for (size_t i = 0; i < arity; ++i) { ObtainType<Args...>(i,args[i]); } cont_[str] = FunctionInfo(func_ptr,ret,args); } void CallFunc(const std::string& func_name,std::vector<boost::variant<int,double>>& args_vec) { auto it = cont_.find(func_name); if (it != cont_.end()) { // ??????? // And here I stucked } } private: std::map<std::string,FunctionInfo> cont_; };
然后我卡住了
>不知道如何从我的结构体获取函数类型信息:).
>不知道如何将变体的向量转换为参数列表.
也许我的路径错了?你能建议任何解决这个问题,除了Lua这样的脚本引擎吗?
解决方法
你可以这样做:
class BaseFunc { public: virtual ~BaseFunc() = default; virtual void Call(std::vector<boost::variant<int,double>>& args_vec) const = 0; }; template <typename F> class Function; template <typename R,typename... Args> class Function<R(Args...)> : public BaseFunc { public: Function(R (*f)(Args...)) : f(f) {} void Call(std::vector<boost::variant<int,double>>& args_vec) const override { Call(args_vec,std::index_sequence_for<Args...>()); } private: template <std::size_t ... Is> void Call( std::vector<boost::variant<int,double>>& args_vec,std::index_sequence<Is...>) const { // Add additional check here if you want. f(boost::get<Args>(args_vec.at(Is))...); } private: R (*f)(Args...); };