Lorac Lorac - 3 months ago 9
C++ Question

Using the value that any_of finds to use in a return outside 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);

Answer

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.