10

I have a function that searches a vector of iterators and returns the iterator if its names matches a string passed as an argument.

koalaGraph::PVertex lookUpByName(std::string Name, std::vector<koalaGraph::PVertex>& Vertices) { for (size_t i = 0; i < Vertices.size(); i++) { if(Vertices[i]->info.name == Name) return Vertices[i]; } } 

My question is how can I implement this as a lambda, to use it in connection with std::find_if?

I'm trying this:

std::vector<koalaGraph::PVertex> V; std::string Name; std::find_if(V.begin(), V.end(), [&Name]() {return Name == V->info.name;}) 

But it says that V

an enclosing-function local variable cannot be referenced in a lambda body unless it is in the capture list.

1
  • 1
    No return if nothing found? Commented Mar 19, 2019 at 21:26

5 Answers 5

22

find_if is going to pass the elements of the vector into your lambda. That means you need

std::find_if(V.begin(), V.end(), [&Name](auto const& V) {return Name == V->info.name;}) 

so that the V in the lambda body is the element of the vector, not the vector itself.


Ideally you'd give it a different name than V so you keep the vector and local variables separate like

std::find_if(V.begin(), V.end(), [&Name](auto const& element) {return Name == elememt->info.name;}) 

So now it is clear you are working on a element of the vector, instead of the vector itself.

Sign up to request clarification or add additional context in comments.

Comments

8

First, V->info.name is ill formed, inside or outside of the lambda.

The function object sent to the algoritm std::find_if must be a unary function. It must take the current element to check as a parameter.

auto found = std::find_if( V.begin(), V.end(), [&Name](koalaGraph::PVertex const& item_to_check) { return Name == item_to_check->info.name; } ); 

The type of found is an iterator to the element that has been found. If none is found, then it returns V.end()

If you use C++14 or better, you can even use generic lambdas:

auto found = std::find_if( V.begin(), V.end(), [&Name](auto const& item_to_check) { return Name == item_to_check->info.name; } ); 

4 Comments

V->info.name is valid syntax. It just won't typecheck since vectors don't overload ->.
It just won't typecheck since vectors don't overload -> so... it won't compile? It's an invalid syntax to use -> on object of types that don't overload operator->
Not all compile errors are syntax errors. See syntax vs. semantics.
@SilvioMayolo The answer you linked me says that semantics is the meaning of the program, usually in it's runtime behaviour. The code I quoted is simply ill formed, there is no semantic yet. Or maybe I don't understand the concept correctly
4

std::find_if's predicate will receive a reference to each element of the range in turn. You need:

std::find_if( V.begin(), V.end(), [&Name](koalaGraph::PVertex const &v) { return Name == v->info.name; } ); 

Comments

2

Get V as parameter to the lambda.

std::find_if(V.begin(), V.end(), [&Name](type& V) {return Name == V->info.name;)

Comments

1

Use const auto & to access the individual elements from your vector in the lambda expression. Since the vector is an lvalue, auto will be deduced to const vector<PVertex> &. Then, you can use std::distance to find the element location of the object in the vector.

struct PVertex { std::string name; }; int main() { std::vector<PVertex> V = {{"foo"},{"bar"},{"cat"},{"dog"}}; std::string Name = "cat"; auto found = std::find_if(std::begin(V), std::end(V), [&Name](const auto &v){return (Name == v.name);}); std::cout<< "found at: V["<<std::distance(std::begin(V),found)<<"]" <<std::endl; } 

Result is:

found at: V[2] 

Example: https://rextester.com/IYNA58046

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.