在 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)。
在某些 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)。