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.

jvb
  • 153
  • 1
  • 4
black sheep
  • 369
  • 4
  • 13

5 Answers5

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.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
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;
    }
);
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • `V->info.name` is valid syntax. It just won't typecheck since vectors don't overload `->`. – Silvio Mayolo Mar 19 '19 at 14:31
  • 3
    `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->` – Guillaume Racicot Mar 19 '19 at 14:33
  • 1
    Not all compile errors are syntax errors. See [syntax vs. semantics](https://stackoverflow.com/questions/17930267/what-is-the-difference-between-syntax-and-semantics-of-programming-languages). – Silvio Mayolo Mar 19 '19 at 14:34
  • 2
    @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 – Guillaume Racicot Mar 19 '19 at 14:40
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; }
);
Quentin
  • 62,093
  • 7
  • 131
  • 191
2

Get V as parameter to the lambda.

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

Petar Velev
  • 2,305
  • 12
  • 24
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

Constantinos Glynos
  • 2,952
  • 2
  • 14
  • 32