通过通用参考捕获

Ric*_*ock 20 c++ lambda c++14

将推导出的类型作为r值引用传递时,我会获得通用引用功能,并且可以像这样完美转发:

template <typename T>
void func(T&& t) {
    other_func(std::forward<T>(t));
}
Run Code Online (Sandbox Code Playgroud)

...由于T的推导方式和标准的参考折叠规则.

现在考虑other_func采用一个函数对象

template <typename T>
void func(T&& t) {
    other_func([](int v) { return t + v; }); // I chose addition for example purposes
}
Run Code Online (Sandbox Code Playgroud)

现在很明显,由于没有被捕获,这将无法编译.我的问题是:我如何捕获它,以便捕获的值将是推断出的T值?

这是否可以使用新的通用lambda捕获?如果......怎么样?

[t = std::forward<T>(t)] ? 
Run Code Online (Sandbox Code Playgroud)

我仍然没有真正掌握新捕获初始化器的机制......

Com*_*sMS 8

好的,我们来试试吧.不幸的是,我没有一个支持这个功能的编译器,所以如果我严重误解了整个过程中的事情,请原谅我.

关于此的提案是N3648.

这里有趣的部分是init捕获中变量的类型推断,就像使用auto:

该成员的类型对应于"auto init-capture"形式的假设变量声明的类型.[...].

因此,从捕获列表中获得的内容的问题[c = std::forward<T>(t)]等同于您从声明中获得的内容auto c = std::forward<T>(t).

这里推导出的类型将是std::remove_reference<T>::type(参考限定符被删除auto),因此您将始终在此处获得新值.如果t是右值引用,则将移动构造该新值,否则将复制构造(由于返回值std::forward).

好消息是这个新值由lambda拥有.所以不管t你最初传入的是什么,std::move从被捕获的都是安全的c.因此,即使你不知道最初的类型,t你仍然没有失去任何东西.


Cas*_*sey 6

你可以在C++ 11中"通过通用引用捕获",因为Tlambda函数可以使用模板参数的类型(Coliru的可怕实时代码示例):

template <typename T>
void func(T&& t) {
  other_func([&t](int v) {
    return std::forward<T>(t) + v;
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 一个可能的问题:如果`other_func`存储了lambda并且它持续的时间比`func`的body范围更长,则调用lambda是UB,因为捕获的变量`t`已经离开了scope. (6认同)