Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic generic lambda and function overload

Tags:

c++

c++14

I have the following variadic generic lambda and overloaded foo() function defined.

template <typename Lambda>
auto bar(Lambda&& lambda) {
    return [lambda = std::forward<Lambda>(lambda)](auto&& ...args) {
        return lambda(std::forward<decltype(args)>(args)...);
    };
}

void foo(std::function<void()>&& cmd, std::function<void()>&& callback) { std::cout << "void" << std::endl; }
void foo(std::function<bool()>&& cmd, std::function<bool()>&& callback) { std::cout << "bool" << std::endl; }

The following 3 foo() calls print "void".

int main()
{
    // 1
    foo(
        bar( []() {} ),
        bar( []() {} )
    );
    // 2
    foo(
        bar( []() { return true; } ),
        bar( []() {} )
    );
    // 3
    foo(
        bar( []() {} ),
        bar( []() { return true;} )
    );
    // 4) compiler error: foo is ambiguous
    // foo(
    //     bar( []() { return false; } ),
    //     bar( []() { return true; } )
    // );
}

Could you please help me to understand why it successfully compiles statements 1-3 but fails to compile statement 4?

gcc 7.5.0

like image 386
sergey Avatar asked Jan 25 '23 00:01

sergey


1 Answers

std::function<void()> can store a function with any return type (void or not), its return value is discarded.

Because of that, in (4) both overloads are applicable, and the compiler can't decide which one to use.

In (1), (2), and (3) on the other hand, at least one of the two lambdas returns void, so the bool overload of foo is not applicable.


Possible solutions are:

  • When passing a functor into foo, cast it to a proper specialization of std::function first. (doesn't look too good)

  • Write a custom wrapper/replacement for std::function, with a different SFINAE for the constructor. (takes effort)

  • Make foo a template (use template parameters as types for the callbacks). Then use decltype to determine the return type, and act accordingly. (this is what I would do)

like image 190
HolyBlackCat Avatar answered Feb 04 '23 21:02

HolyBlackCat