如何解决C ++-在Lambda中捕获完美转发的vars
我对c ++还是很陌生,目前正在为我的第一个项目编写一个控制容器的反转版本,在this blog post上进行扩展,方法是在基类上添加注册并将其他参数转发给构造函数。
目前它的效果很好,但是当我多次实例化一个lambda时,捕获的值似乎会被覆盖。
示例:
struct A{
short a;
explicit A(short a_) : a(a_) {}
};
struct IC{
virtual unsigned C() = 0;
};
struct CImpl : public IC{
explicit CImpl(unsigned c_) : IC(),c(c_) {}
unsigned C() override{return c;}
private:
unsigned c;
};
template<class T,typename...TArgs>
std::function<T*()> AsMinimalAsItGets(TArgs&&...args)
{
return [&args...]() mutable -> T*
{
return new T(std::forward<TArgs>(args)...);
};
}
auto aFactory = AsMinimalAsItGets<A>(3);
auto cFactory = AsMinimalAsItGets<CImpl>(5);
auto aInst = aFactory();//aInst->a should be 3 but is 5
auto cInst = cFactory();//cInst->C() is 5
A用5而不是3实例化。
我尝试使用this作为解决方案,但是并不能解决问题。
那么在实例化lambda时如何正确捕获变量? 我需要以一种使我能够在lambda中使用完美转发的方式进行捕获
解决方法
当您实际需要副本时,请勿尝试避免复制。在您的情况下,您尝试通过std::forward
保留参数的值类别。但是,当您返回工厂函数std::function<T*()>
时,此闭包必须拥有用于执行延迟构造的数据。否则,最终将导致悬挂引用,因为传递给AsMinimalAsItGets
的参数只会超出函数调用的范围。
修复很容易:
template<class T,typename...TArgs>
std::function<T*()> AsMinimalAsItGets(TArgs&&...args)
{
return [args...]() mutable -> T*
// ^^^^^^^ (1) Copy the arguments into the closure
{
return new T(args...);
// ^^^^^^^ (2) Pass them as is to the ctor
};
}
请注意,正如@HolyBlackCat指出的那样,这不能将参数完美地转发到lambda捕获中。如this answer所示,在C ++ 20中,您可以
return [...args = std::forward<TArgs>(args)]() mutable -> T*
{
return new T(args...);
};
在C ++ 17中,您需要以下解决方法:
return [args = std::make_tuple(std::forward<TArgs>(args)...)]() mutable -> T*
{
return std::apply([](auto&&... args){ return new T(args...); },std::move(args));
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。