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