YSC*_*YSC 16 c++ lambda perfect-forwarding c++14
我想出了以下代码将R()alike转换为类似void()callable:
#include <utility>
template<class Callable>
auto discardable(Callable&& callable)
{ return [&]() { (void) std::forward<Callable>(callable)(); }; }
// ^-- is it ok?
int main()
{
auto f = discardable([n=42]() mutable { return n--; });
f();
}
Run Code Online (Sandbox Code Playgroud)
我很担心被引用捕获.
callable永远不会复制,并且在其生命周期结束后从未使用过吗?这是标记的C++ 14,但适用于所有以下标准.
Pas*_* By 13
Lambdas是带有a的匿名结构operator(),捕获列表是一种指定其成员类型的奇特方式.通过引用捕获真的就是听起来像:你有参考成员.不难看出参考悬挂.
在这种情况下,您特别不希望完全转发:根据参数是左值还是右值引用,您有不同的语义.
template<class Callable>
auto discardable(Callable& callable)
{
return [&]() mutable { (void) callable(); };
}
template<class Callable>
auto discardable(Callable&& callable)
{
return [callable = std::forward<Callable>(callable)]() mutable { // move, don't copy
(void) std::move(callable)(); // If you want rvalue semantics
};
}
Run Code Online (Sandbox Code Playgroud)
因为callable可以是一个xvalue,它有可能在lambda捕获之前被破坏,因此在捕获中留下一个悬空引用.为了防止这种情况,如果参数是r值,则需要复制它.
一个工作的例子:
template<class Callable>
auto discardable(Callable&& callable) { // This one makes a copy of the temporary.
return [callable = std::move(callable)]() mutable {
static_cast<void>(static_cast<Callable&&>(callable)());
};
}
template<class Callable>
auto discardable(Callable& callable) {
return [&callable]() mutable {
static_cast<void>(callable());
};
}
Run Code Online (Sandbox Code Playgroud)
如果callable是l值引用但是它的生命周期范围小于返回的lambda捕获的范围,则仍然可能面临生命周期问题discardable.因此,始终移动或复制可能是最安全和最容易的callable.
作为旁注,尽管有新的专用实用程序可以完美地转发函数对象的值类别std::apply,但标准库算法总是通过按值接受它们来复制函数对象.因此,如果一个重载operator()()&,operator()()&&标准库将始终使用operator()()&.
当您使用捕获的lambda的悬空参考时,您的程序是UB.
因此,为了完善lambda中的前向捕获,您可以使用
template<class Callable>
auto discardable(Callable&& callable)
{
return [f = std::conditional_t<
std::is_lvalue_reference<Callable>::value,
std::reference_wrapper<std::remove_reference_t<Callable>>,
Callable>{std::forward<Callable>(callable)}]
{
std::forward<Callable>(f)();
};
}
Run Code Online (Sandbox Code Playgroud)
它移动构造临时lambda.
| 归档时间: |
|
| 查看次数: |
1058 次 |
| 最近记录: |