Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ lambda doesn't deduce function overloading

I'm defining a class like this:

class foo {
public:
  // I define const and non-const versions of the 'visit' function
  // nb. the lambda is passed by reference
  virtual void visitWith(std::function<void(foo&)>&);
  virtual void visitWith(std::function<void(const foo&)>&) const;
};

foo can have children so the idea is to visit a foo and all it's children recursively.

When I try to use it, eg. like this:

foo f;
f.visitWith([&](const foo&) {
  // Do something here
});

I get compiler errors. The compiler can't figure out what to do.

I can make it work it by adding a typecast like this:

foo f;
f.visitWith( (std::function<void(const foo&)>) [&](const foo&) {
  // Do something here
});

But that's horrible.

How can I get it to work neatly?

Edit:

This may be a problem with Visual C++, it refuses to compile the code given here:

https://ideone.com/n9bySW

The VC++ output when I try to compile it is:

I get this error in Visual C++

Edit2: Nope, Visual C++ is correct, the code is ambiguous. See my solution below...

like image 618
Chifti Saidi Avatar asked Mar 02 '23 00:03

Chifti Saidi


1 Answers

A lambda is a compiler-generated type, it is not an instance of std::function, but it is assignable to one.

Your visitWith() method takes a std::function by non-const reference, which means it requires a pre-existing std::function object, eg:

std::function<void(const foo&)> func = [&](const foo&) {
    // Do something here
};
foo f;
f.visitWith(func);

Passing a lambda directly to visitWith() would require the compiler to create a temporary std::function object, but a non-const reference cannot bind to a temporary object. That is why your original code fails to compile.

For what you are attempting, you will have to pass the std::function either by value or by const-reference instead:

class foo {
public:
    void visitWith(std::function<void(foo&)>);
    void visitWith(std::function<void(const foo&)>) const;
};

Live Demo

class foo {
public:
    void visitWith(const std::function<void(foo&)> &);
    void visitWith(const std::function<void(const foo&)> &) const;
};

Live Demo

like image 130
Remy Lebeau Avatar answered Mar 11 '23 08:03

Remy Lebeau