C++模板:Ret(Arg...)的相关

cpp 复制代码
先看一个不保存东西,只解析类型的:

template<typename T>
struct FuncTraits;

// 偏特化:拆解函数类型 R(Args...)
template<typename R, typename... Args>
struct FuncTraits<R(Args...)> {
    using ReturnType = R;
    using ArgsTuple = std::tuple<Args...>;

    static constexpr std::size_t kArity = sizeof...(Args);
};

测试:
    {
        FuncTraits<int(double, char)>::ReturnType i;
        FuncTraits<void()>::ReturnType* j;
        FuncTraits<int(double, char)> o;

        std::ignore = i;
        std::ignore = j;
        std::ignore = o;
    }

如果要保存函数级的变量呢,可能没那么简单。

下面是可以保存lambda的例子(模仿std::function?比如要达成这样的效果:std::function<int(int)> cb1(\[\](int x) { return x; });),一步一步:

cpp 复制代码
template<typename FuncSignature>
struct CallableImplX;

template<typename Ret, typename... Args>
struct CallableImplX<Ret(Args...)>
{

public:
    template<typename _functor>
    explicit CallableImplX(_functor&& f) //: func_(std::move(f))
    {
        std::ignore = 0;
    }
};

引用:
编译通过:
auto lmd = [](int a, int b) ->int {
            return a + b;
        };

CallableImplX<int(int, int)>* p = new CallableImplX<int(int, int)>([](int a, int b) {
            return a + b;
        });
或者自动推导:
auto* p = new CallableImplX<int(int, int)>([](int a, int b) {
            return a + b;
        });

注意,构造函数也是个模板,
由于_functor是在调用构造函数时推导的,
如果没有额外检查的逻辑的话(比如赋值给某个变量),
传入什么参数都可以:
template<typename _functor>
    explicit CallableImplX(_functor f) //: func_(std::move(f))
    {
        std::ignore = 0;
    }

所以,下面的代码也能顺利编译通过:
auto* p2 = new CallableImplX<int(int, int)>(1);
std::ignore = p2;
cpp 复制代码
如果简单的用Ret和Args...组合成函数类型,定义一个成员变量来接收呢?

template<typename FuncSignature>
struct CallableImplX;

template<typename Ret, typename... Args>
struct CallableImplX<Ret(Args...)>
{
    using _funcSig = Ret(Args...); //重新组装成函数类型

public:
    template<typename _functor>
    explicit CallableImplX(_functor&& f) //: func_(std::move(f))
    {
        this->func_ = f; //这个地方,赋值给成员变量。这个地方,编译器会检查。
        std::ignore = 0;
    }

private:
    _funcSig func_; //声明一个成员变量
};

引用:
编译错误:
错误	C2659	"=": 作为左操作数

auto lmd = [](int a, int b) ->int {
            return a + b;
        };

auto* p = new CallableImplX<int(int, int)>([](int a, int b) {
            return a + b;
        });

如何保存呢:

cpp 复制代码
template<typename FuncSignature>
struct CallableImplX;

template<typename Ret, typename... Args>
struct CallableImplX<Ret(Args...)>
{
    using _funcSig = Ret(Args...);

public:
    template<typename _functor>
    explicit CallableImplX(_functor&& f) //: func_(std::move(f))
    {
        this->func_ = f; //这个地方可以正常接收了。
而且std::function也根据Ret(Args...)指定了同样的类型了,所以肯定是没错的
        std::ignore = 0;
    }

private:
    std::function<_funcSig> func_; //用std::function来接收吧
};

引用:
编译通过:
auto lmd = [](int a, int b) ->int {
            return a + b;
        };

auto* p = new CallableImplX<int(int, int)>([](int a, int b) {
            return a + b;
        });

CallableImplX<int(int, int)> o{ [](int a, int b) {
            return a + b;
        } };

但下面会编译出错:
CallableImplX<int(int, int)> o1 = [](int a, int b) {
    return a + b;
   };

错误信息:
CallableImpl<int <lambda>(int, int),int,int,int>::CallableImpl<int <lambda>(int, int),int,int,int>
(
   main::__l3::int <lambda>(int, int) f=int <lambda>(int a, int b){...}
)

FunctorWrapper<int __cdecl(int,int)>::FunctorWrapper<int __cdecl(int,int)>
<
int <lambda>(int, int) >(main::__l3::int <lambda>(int, int) && f=int <lambda>(int a, int b){...}
)

根据AI分析,原因是:
// 错误:explicit构造函数禁止隐式转换
把CallableImplX前面的explicit去掉就能编译通过。

CallableImplX内部存储的是std::function<Ret(Args...)>,而lambda的签名是int(int, int),虽然看起来匹配,但由于构造函数的explicit限制,仍然无法进行隐式转换

擦除型的:

cpp 复制代码
// 抽象基类:定义统一的调用接口
template<typename Ret, typename... Args>
class CallableBase {
public:
    virtual ~CallableBase() = default;
    virtual Ret invoke(Args... args) const = 0;
    virtual CallableBase* clone() const = 0;
};

// 模板子类:存储具体的可调用对象
template<typename F, typename Ret, typename... Args>
class CallableImpl : public CallableBase<Ret, Args...> {
public:
    explicit CallableImpl(F f) : func_(std::move(f)) {
        std::ignore = 0;
    }

    Ret invoke(Args... args) const override {
        return func_(std::forward<Args>(args)...);
    }

    CallableBase<Ret, Args...>* clone() const override {
        return new CallableImpl(func_);
    }

private:
    F func_; // 存储lambda的副本
};


// 主模板:接收可调用对象,使用类型擦除
template<typename Signature>
class FunctorWrapper;

// 偏特化:处理具体的函数签名
template<typename Ret, typename... Args>
class FunctorWrapper<Ret(Args...)> {
public:
    // 模板构造函数:接收任意可调用对象
    template<typename F>
    FunctorWrapper(F&& f)
        : impl_(new CallableImpl<std::decay_t<F>, Ret, Args...>(std::forward<F>(f))) {}

    // 拷贝构造
    FunctorWrapper(const FunctorWrapper& other)
        : impl_(other.impl_ ? other.impl_->clone() : nullptr) {}

    // 移动构造
    FunctorWrapper(FunctorWrapper&& other) noexcept
        : impl_(other.impl_) {
        other.impl_ = nullptr;
    }

    // 析构
    ~FunctorWrapper() {
        delete impl_;
    }

    // 调用操作符
    Ret operator()(Args... args) const {
        if (!impl_) {
            throw std::runtime_error("Calling empty FunctorWrapper!");
        }
        return impl_->invoke(std::forward<Args>(args)...);
    }

    // 判断是否为空
    explicit operator bool() const {
        return impl_ != nullptr;
    }

private:
    CallableBase<Ret, Args...>* impl_ = nullptr;
};

测试:
// 1. 接收无捕获的lambda
FunctorWrapper<int(int, int)> adder = [](int a, int b) {
      return a + b;
};
std::cout << "adder(3, 4) = " << adder(3, 4) << std::endl; // 输出7
相关推荐
Zixhy11 分钟前
手撕Reactor模型实现同步高并发服务器及Muduo网络库深入解析
linux·服务器·网络·数据库·c++
傻啦嘿哟7 小时前
某招聘平台爬虫:爬取招聘岗位数据,分析各城市薪资水平
开发语言·爬虫·python
2501_933670797 小时前
2026秋招量化分析岗技能栈:Python、SQL、统计建模、回测项目怎么准备
开发语言·python·sql
Dola_Zou7 小时前
工厂智能排产软件算法保护与按产线计费实战
算法·自动化·软件工程·软件加密
李少兄7 小时前
JavaScript 数据类型完全指南
开发语言·javascript·ecmascript
码匠许师傅8 小时前
【设计模式精讲】29.行为型模式总结与对比(Behavioral Patterns Summary)
c++·设计模式·uml
Seoyoneh8 小时前
Agentic Workflow编排架构:云客服从“被动响应”迈向“主动执行”的技术实现
java·开发语言·架构
啦啦啦啦啦zzzz8 小时前
Logger的组装(c++20)
c++·算法·c++20
Tangyuewei8 小时前
Java 写 Agent:模型只是组件
java·开发语言
小玮看世界9 小时前
[Python]从合并区间到传感器融合区:合并区间在传感器区域融合的实际落地
开发语言·python