在 STL 谓词中使用完美转发

Using perfect fowarding in STL predicate

在某些 STL 算法中使用完美转发是否有意义?推导的类型是什么?

auto it = std::find_if(cont.cgebin(),
                       cont.cend(),
                       [](auto&& element){ return myFunction(std::forward<decltype(element)>(element)); })

我想将使用 L 值版本(const 怎么样?),但是什么决定了它?还有其他算法会发送 R 值吗?我不这么认为,因为这意味着无论谓词的结果如何,谓词都可以“消耗”元素。

一般来说,完美转发一个参数是有意义的,但这取决于它的内部结构:myFunction 是否利用了转发?

在这种特殊情况下 - 作为谓词 - 不推荐:我认为 find_if 在调用谓词时从不移动元素。

但如果会的话:

  • 如果 myFunction 通过左值引用接受它的参数,那么什么也不会发生,因此与简单的 const auto& 情况相比,完美转发只是句法噪音。
  • 另一方面:如果 myFunction 可以通过右值引用获取它的参数(使用它),那么 find_if 将 return 是 moved-from 中元素的迭代器状态。并且所有其他元素都将被移动,其使用谓词进行检查。这就是为什么我认为 find_if 没有 move 用于检查谓词的元素。

对于其他算法,例如 std::accumulate 忽略右值引用大小写可能会导致性能问题。

element 的推导类型取决于 lambda 在 find_if 中的使用方式。

find_if 永远不会自行移动(您可以将可移动迭代器传递给 find_if,但这样移动的不是 find_if,而是迭代器)。 find_if 会将解引用运算符 returned 的值传递给 lambda,因此在您的情况下,它很可能是 1 const T& (很可能是 T& 如果你有一个非常量容器并使用 begin/end).

const T&T&两种情况下,std::forward什么都不做,所以你只需将参数传递给myFunction

请注意,标准要求 std::find_if 的谓词不修改其参数,因此如果您有 myFunction(T&) 修改其参数,则您的代码具有未定义的行为。

你应该而不是 std::forward,因为没有理由接受 find_if 中使用 const T& 以外的任何参数,所以更好的版本是2:

auto it = std::find_if(cont.cbegin(), cont.cend(),
                       [](const auto& element){ return myFunction(element); });

1 一些奇怪的容器 (std::vector<bool>) 不会 return 一个 const bool& 而是一个代理对象,所以你的 lambda 需要取 const auto&auto&&auto& 将是一个编译时错误。

2 有些人(很多?)在这种情况下使用 auto&& 没有 std::forward 当然,因为它更短并且给你一致的 lambda(你在任何地方都使用 auto&& 作为 lambda)。