You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:39:53