C++模板参数推导及无模板基类封装多返回类型函数问题
可封装函数的Functor类技术问题解答
原始实现代码
#include <tuple> #include <stdlib.h> #include <iostream> #include <QSharedPointer> template <class PARENT> class FunctorHandlerBase { public: typedef typename PARENT::TRET RTYPE; typedef typename PARENT::TUP ARGS; virtual RTYPE operator()(ARGS) { return RTYPE(0); }; }; template <class PARENT, typename MFUN> class FunctorHandler : public FunctorHandlerBase<PARENT> { public: typedef typename PARENT::TRET RTYPE; typedef typename PARENT::TUP ARGS; FunctorHandler(MFUN pfun) : pFun(pfun) {} virtual ~FunctorHandler() {}; virtual RTYPE operator()(ARGS args) { return callPrivate(args, std::make_index_sequence<std::tuple_size_v<decltype(args)>>{}); } private: template<class Tuple, std::size_t... Is> RTYPE callPrivate(Tuple&& tuple, std::index_sequence<Is...>) { return (*pFun)(std::get<Is>(std::forward<Tuple>(tuple))...); } MFUN pFun; }; template <class PARENT, class POBJ, typename MFUN> class MFunctorHandler : public FunctorHandlerBase<PARENT> { public: typedef typename PARENT::TRET RTYPE; typedef typename PARENT::TUP ARGS; MFunctorHandler(const POBJ &pobj, MFUN pfun) : pObj(pobj), pFun(pfun) {} virtual ~MFunctorHandler() {}; virtual RTYPE operator()(ARGS args) { return callPrivate(args, std::make_index_sequence<std::tuple_size_v<decltype(args)>>{}); } private: template<class Tuple, std::size_t... Is> RTYPE callPrivate(Tuple&& tuple, std::index_sequence<Is...>) { return ((*pObj).*pFun)(std::get<Is>(std::forward<Tuple>(tuple))...); } POBJ pObj; MFUN pFun; }; template <typename RTYPE = void> class FunctorBase { public: virtual RTYPE operator()() { return RTYPE(0); } }; template <typename RTYPE = void, class... Args> class Functor : public FunctorBase<RTYPE> { public: typedef RTYPE TRET; typedef typename std::tuple<Args ...> TUP; template<typename MFUN> Functor(MFUN pfun, Args&&... args) : mArgs(args...) { pImpl = QSharedPointer<FunctorHandlerBase<Functor>>(new FunctorHandler<Functor, MFUN>(pfun)); } template<class POBJ, typename MFUN> Functor(const POBJ &pobj, MFUN pfun, Args&&... args) : mArgs(args...) { pImpl = QSharedPointer<FunctorHandlerBase<Functor>>(new MFunctorHandler<Functor, POBJ, MFUN>(pobj, pfun)); } RTYPE operator()() { return (*pImpl)(mArgs); } std::tuple<Args ...> mArgs; private: QSharedPointer<FunctorHandlerBase<Functor>> pImpl; }; template<typename RTYPE, class POBJ, typename MFUN, class... Args> FunctorBase<RTYPE> *Create(const POBJ &pobj, MFUN pfun, Args&& ...args) { return new Functor<RTYPE, Args...>(pobj, pfun, std::forward<Args...>(args)...); } class B { public: B(){}; bool voidF() { return true; } bool printInt(int x) { std::cout << "print int:" << x; return true; } }; int main(int argc, char *argv[]) { B *b = new B; auto *fb = Create<bool>(b, &B::printInt, 100); std::cout << "function result" << (*fb)(); }
技术问题
- 能否在Create函数中从函数指针自动推导返回类型,将调用语句从
auto *fb = Create<bool>(b, &B::printInt, 100)改为auto *fb = Create(b, &B::printInt, 100)? - 能否创建无模板参数的Functor基类,以便将不同返回类型的函数存入vector,并通过
std::is_same_v获取函数返回类型?目前仅能存入同一返回类型的函数。
问题解答
1. 自动推导返回类型的实现
可以实现,核心是利用C++的类型萃取工具从函数/成员函数指针中提取返回类型,无需显式指定模板参数。
修改Create函数,移除显式的RTYPE模板参数,改用std::invoke_result_t自动推导调用后的返回类型:
#include <type_traits> // 处理成员函数的Create重载 template<class POBJ, typename MFUN, class... Args> auto Create(const POBJ &pobj, MFUN pfun, Args&& ...args) { using RTYPE = std::invoke_result_t<MFUN, POBJ, Args...>; return new Functor<RTYPE, Args...>(pobj, pfun, std::forward<Args>(args)...); } // 处理普通函数的Create重载(如需支持) template<typename MFUN, class... Args> auto Create(MFUN pfun, Args&& ...args) { using RTYPE = std::invoke_result_t<MFUN, Args...>; return new Functor<RTYPE, Args...>(pfun, std::forward<Args>(args)...); }
修改后,调用时即可省略返回类型模板参数:
auto *fb = Create(b, &B::printInt, 100);
2. 无模板基类实现多返回类型存储
可以创建一个无模板的根基类,让所有FunctorBase<RTYPE>继承它,并在根基类中添加返回类型查询接口,从而实现不同返回类型的Functor存入同一容器。
步骤1:定义无模板根基类
#include <typeinfo> class FunctorRoot { public: virtual ~FunctorRoot() = default; virtual const std::type_info& getReturnType() const = 0; };
步骤2:修改FunctorBase继承关系
template <typename RTYPE = void> class FunctorBase : public FunctorRoot { public: virtual RTYPE operator()() = 0; const std::type_info& getReturnType() const override { return typeid(RTYPE); } };
步骤3:存入vector并检查返回类型
现在可以将不同返回类型的Functor存入vector<FunctorRoot*>,并通过getReturnType()结合std::is_same_v或typeid比较来判断返回类型:
#include <vector> int main() { B* b = new B; std::vector<FunctorRoot*> funcVec; funcVec.push_back(Create(b, &B::printInt, 100)); funcVec.push_back(Create(b, &B::voidF)); // 遍历处理不同返回类型 for (auto* func : funcVec) { if (func->getReturnType() == typeid(bool)) { auto* boolFunc = dynamic_cast<FunctorBase<bool>*>(func); if (boolFunc) { bool result = (*boolFunc)(); std::cout << "\nBool result: " << std::boolalpha << result << std::endl; } } } // 释放内存 for (auto* func : funcVec) delete func; delete b; return 0; }
如果要使用std::is_same_v,可以封装一个判断函数:
template<typename T> bool isReturnType(FunctorRoot* func) { return std::is_same_v<T, typename std::decay_t<decltype(typeid(T))>> && func->getReturnType() == typeid(T); } // 使用示例 if (isReturnType<bool>(func)) { // 处理逻辑 }
内容的提问来源于stack exchange,提问作者Caboom Bom
相关产品推荐
相关产品推荐

