指向 lambda 的智能指针
Smart pointer to lambda
我正在尝试创建一个接受指向某个仿函数的共享指针的函数。使用手动制作的函子没有问题,但使用 lambda 时有问题。我知道我不能将 decltype
与 lambda 一起使用 - 每个新的 lambda 声明都会创建一个新类型。现在我在写:
auto lambda = [](int a, float b)->int
{
return 42;
};
using LambdaType = decltype(lambda);
shared_ptr<LambdaType> ptr{ new LambdaType{ lambda } };
它可以工作,但看起来很丑。此外还有一个复制构造函数调用!有什么办法可以简化吗?
您可以使用 std::function 作为类型。
Lambdas 只是自动编写的可调用对象,使简单的代码变得简单。如果你想要一些超出他们默认自动存储行为的东西,写他们自己写的类型。
在未计算的上下文中使用 lambda 类型是非法的。在评估的上下文中,它在自动存储中创建一个 lambda。你想要它在免费商店。这至少在逻辑上需要一个副本。
一个可怕的 hack,涉及违反未评估的上下文规则,sizeof/alignof,aligned_storage_t,放置新的,可能是无限的编译时间递归(或者可能是 static_assert
),返回指针到局部变量和共享 ptr 的别名构造函数,并要求调用者编写疯狂的代码可能会避免调用 copy/move。但这是个坏主意,简单地使用可调用对象更容易。
当然,接受 copy/move 会使它变得微不足道。但是在那个时候,只要使用 std::function
除非你需要像 varargs 这样的东西。
你说你不想强迫用户使用 std::function
;但是 std::function
会将兼容的 lambda 隐式转换为自身。
如果您愿意接受副本,我们可以这样做:
template<class T>
std::shared_ptr<std::decay_t<T>>
auto_shared( T&& t ) {
return std::make_shared<std::decay_t<T>>(std::forward<T>(t));
}
然后 auto ptr = auto_shared( [x=0]()mutable{ return x++; } );
是指向计数 lambda 的非类型擦除共享指针。 lambda 被复制(嗯,移动)到共享存储中。
如果您想避免该副本,客户端可以编写一个手动函数对象并对其调用make_shared<X>(ctor_args)
。
目前没有合理的方法将 lambdas 类型与其在 C++ 中的构造分开。
如果你在 lambda 中捕捉到一些东西,它在算法上与 std::function
相同,所以可以自由使用它。此外,std::function
实现了捕获值内存管理,因此不需要在其之上使用 std::shared_ptr
。
如果你什么都没发现,lambda 可以转换为简单的函数指针:
int(*ptr)(int,int) = [](int a, int b) -> int {
return a+b;
};
函数是静态分配的,绝对不应该被删除。所以,你实际上并不需要 std::shared_ptr
我正在尝试创建一个接受指向某个仿函数的共享指针的函数。使用手动制作的函子没有问题,但使用 lambda 时有问题。我知道我不能将 decltype
与 lambda 一起使用 - 每个新的 lambda 声明都会创建一个新类型。现在我在写:
auto lambda = [](int a, float b)->int
{
return 42;
};
using LambdaType = decltype(lambda);
shared_ptr<LambdaType> ptr{ new LambdaType{ lambda } };
它可以工作,但看起来很丑。此外还有一个复制构造函数调用!有什么办法可以简化吗?
您可以使用 std::function 作为类型。
Lambdas 只是自动编写的可调用对象,使简单的代码变得简单。如果你想要一些超出他们默认自动存储行为的东西,写他们自己写的类型。
在未计算的上下文中使用 lambda 类型是非法的。在评估的上下文中,它在自动存储中创建一个 lambda。你想要它在免费商店。这至少在逻辑上需要一个副本。
一个可怕的 hack,涉及违反未评估的上下文规则,sizeof/alignof,aligned_storage_t,放置新的,可能是无限的编译时间递归(或者可能是 static_assert
),返回指针到局部变量和共享 ptr 的别名构造函数,并要求调用者编写疯狂的代码可能会避免调用 copy/move。但这是个坏主意,简单地使用可调用对象更容易。
当然,接受 copy/move 会使它变得微不足道。但是在那个时候,只要使用 std::function
除非你需要像 varargs 这样的东西。
你说你不想强迫用户使用 std::function
;但是 std::function
会将兼容的 lambda 隐式转换为自身。
如果您愿意接受副本,我们可以这样做:
template<class T>
std::shared_ptr<std::decay_t<T>>
auto_shared( T&& t ) {
return std::make_shared<std::decay_t<T>>(std::forward<T>(t));
}
然后 auto ptr = auto_shared( [x=0]()mutable{ return x++; } );
是指向计数 lambda 的非类型擦除共享指针。 lambda 被复制(嗯,移动)到共享存储中。
如果您想避免该副本,客户端可以编写一个手动函数对象并对其调用make_shared<X>(ctor_args)
。
目前没有合理的方法将 lambdas 类型与其在 C++ 中的构造分开。
如果你在 lambda 中捕捉到一些东西,它在算法上与 std::function
相同,所以可以自由使用它。此外,std::function
实现了捕获值内存管理,因此不需要在其之上使用 std::shared_ptr
。
如果你什么都没发现,lambda 可以转换为简单的函数指针:
int(*ptr)(int,int) = [](int a, int b) -> int {
return a+b;
};
函数是静态分配的,绝对不应该被删除。所以,你实际上并不需要 std::shared_ptr