Using the value that any_of finds to use in a return outside lambda

时间:2016-08-31 17:24:52

标签: c++ c++11 lambda

A working piece of code:

std::vector<double>::iterator it = std::find_if(intersections.begin(), intersections.end(), [&](const double i) {return i >= 0;});
if (it != intersections.end())
    return rayOrigin + *(it) * rayDirection);

But I would like to use something like this

Is there a way to capture the i in a clean way (not using a temp variable), that the any_of finds here to use it in the return statement

if (std::any_of(intersections.begin(), intersections.end(), [&](const double i) {return i >= 0;}))
    return rayOrigin + i * rayDirection);

2 个答案:

答案 0 :(得分:3)

I'd write a range-based searcher that returns an object which can be * dereferenced (maybe more than once) to get the found thing, or evaluated in a bool context to determine if it was found.

In my experience this makes code cleaner, and makes the common case of "I want to know if it is there" simpler, yet permits you to get at the item tersely:

template<class Range, class F>
auto linear_search_if( Range&& r, F&& f )
// remove next line in C++14, it removes ADL `begin` capability:
-> typename std::iterator_traits<decltype( std::begin(r) )>::value_type*
// reproducing ADL begin in C++11 is a pain, so just use the above line
{
  using std::begin;  using std::end;
  using iterator = decltype(begin(r));
  using T = typename std::iterator_traits<iterator>::value_type;
  using R = T*; // in C++17 I prefer std::optional<iterator>;
  iterator it = std::find_if( begin(r), end(r), std::forward<F>(f) );
  if (it != end(r))
    return R(std::addressof(*it)); // return R(it); in C++17
  else
    return R(nullptr); // return R{}; in C++17
}

if (auto pi = linear_search_if( intersections, [&](auto i){return i>=0;})
  return rayOrigin + *pi * rayDirection; // **pi in C++17

Yes, you do a *pi instead of just an i.

答案 1 :(得分:2)

是的,find_ifany_of的当前方式有点烦人。 @Yakk的解决方案是通过在std::find_if周围编写一个包装器来返回std::optional<int>来测试成功并有条件地提取结果。对于STL的下一个版本来说,这无疑是一种前进的方式。

然而,在C ++ 17中,你可以move initializers into selection statements消除了大部分的痛苦:

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    auto const v = std::vector<int> { -2, -1, 0, 1, 2 };
    auto const pred = [&](const int i) { return i >= 0; };

    if (auto const it = std::find_if(v.begin(), v.end(), pred); it != v.end())
        std::cout << *it << '\n';      
}

Live Example在c ++ 1z模式下使用最近的Clang。