An overloaded function should take both functors in, given the type of the lambda is decidable ( castable to an std::function
(please correct me if I'm wrong ).
The question is: Why is there a compile error below, despite the lambda type being explicitly defined? ( [&]() -> Type {}
)
Please note, that for my current solution I need the capture-by-reference, that is why the code contains the logic for it.
The following example describes the problem:
#include <iostream>
#include <string>
#include <functional>
void do_some(std::function<void(int)> thing)
{
thing(5);
}
void do_some(std::function<bool(int)> thing)
{
if (thing(10))
{
std::cout << "it's true!" << std::endl;
}
}
int main()
{
int local_to_be_modified = 0;
do_some(
[&](int in)
{
local_to_be_modified = in;
std::cout << "This is void-" << std::endl;
}
);
do_some(
[&](int in) -> bool
{
// error: call to 'do_some' is ambiguous
local_to_be_modified += in;
std::cout << "This is bool-" << std::endl;
return true;
}
);
}
Because the 2nd lambda expression returning bool
could convert to both std::function<void(int)>
and std::function<bool(int)>
implicitly.
std::function
has a converting constructor:
template< class F > function( F f );
This constructor does not participate in overload resolution unless f is Callable for argument types Args... and return type R. (since C++14)
As the definition of Callable,
The following expressions must be valid:
INVOKE<R>(f, std::declval<ArgTypes>()...)
where INVOKE(f, t1, t2, ..., tN) is defined as
static_cast<void>(INVOKE(f, t1, t2, ..., tN))
if R is possibly cv-qualifiedvoid
, otherwise INVOKE(f, t1, t2, ..., tN), implicitly converted to R
Note that the 2nd lambda returning bool
, for the std::function<void(int)>
, as shown above, static_cast<void>(INVOKE(f, t1, t2, ..., tN))
is a valid expression (the returned bool
is just converted to void
). Then it could also convert to std::function<void(int)>
implicitly and causes the ambiguity issue.
You can explicitly static_cast
the lambda to the proper type
using FunBoolRet = std::function<bool(int)>;
do_some(static_cast<FunBoolRet >([&](int in)
{
local_to_be_modified += in;
std::cout << "This is bool-" << std::endl;
return true;
}));
Or store the lambda to the proper std::function<bool(int)>
type and pass to the function(if do_some(lmda)
should be called many times)
FunBoolRet lmda = [&](int in)
{
local_to_be_modified += in;
std::cout << "This is bool-" << std::endl;
return true;
};
do_some(lmda); // pass the lambda
Or as @MaxLanghof suggested
simply construct std::function<bool(int)>
from lambda on the go
do_some(FunBoolRet{
[&](int in)
{
local_to_be_modified += in;
std::cout << "This is bool-" << std::endl;
return true;
}
});
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