1

At the moment I'm trying to build something like a Java-like forEach in a class where I pass a lambda and it gets called for every item. At the moment I've implemented it like this:

Foo.h

class Foo
{
public:
    Foo();
    void forEach(void(*lambda)(Bar*));
private:
    SpecialList mElements;
};

Foo.cpp

#include "Foo.h"

void Foo::forEach(void(*lambda)(Bar*))
{
    for (auto& v : mElements)
    {
        // Try/catch for stopping
        try {lambda(&v.second);}
        catch (int) {break;}
    }
}

main.cpp

int main() {
    Foo foo();
    foo.forEach([](Bar* bar) {
        std::cout << bar->something() << std::endl;
    });
    return 0;
}

It works just fine, but I want to be able to pass elements by reference into the lambda to be able to work with later like in this example:

main.cpp

int main() {
    Foo foo();
    foo.forEach([&var1](Bar* bar) {
        std::cout << var1 << bar->something() << std::endl;
    });
    return 0;
}

How could we achieve something like this? I've been trying but it gives the error no suitable conversion function from... to... and tried searching for previous questions and taking a look at how functions like std::for_each work but cannot make heads or toes of that. Thanks.

4
  • 2
    Take a look at std::function Commented Jul 21, 2020 at 9:07
  • 1
    You could use from std::function and pass reference to data as another argument. Commented Jul 21, 2020 at 9:09
  • C++11 offers such functionality. Look at: en.cppreference.com/w/cpp/algorithm/for_each Commented Jul 21, 2020 at 9:15
  • [OT]: Better to have void(*func)(Bar&) instead of void(*func)(Bar*) as Bar cannot be nullptr Commented Jul 21, 2020 at 10:29

1 Answer 1

4

A lambda is not a function pointer. If it has no captured objects, it can be implicitly converted to one, otherwise it cannot.

A lambda has a anonymous type, so if you want to use the type directly, you need to use templates:

template<typename Callable>
void Foo::forEach(Callable lambda)
{
    for (auto& v : mElements)
    {
        // Try/catch for stopping
        try {lambda(&v.second);}
        catch (int) {break;}
    }
}

Otherwise, a lambda is always convertable to a std::function (even when you capture objects), so you could write like this:

void Foo::forEach(std::function<void(Bar*)> lambda)
{
    for (auto& v : mElements)
    {
        // Try/catch for stopping
        try {lambda(&v.second);}
        catch (int) {break;}
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Hi, I've tried both sugestions and the second one worked just fine.
@Onelio, first should also work. Note that you have to put the definition in the header file as well - otherwise you will get linker errors.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.