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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With