Reputation: 42371
#include <type_traits>
template<typename T, typename... Args_>
concept IsCallable = std::is_invocable_v<T, Args_...>;
struct A
{
int n = 0;
void f(IsCallable<int&> auto const fn)
{
fn(n);
}
void f(IsCallable<int const&> auto const fn) const
{
fn(n);
}
};
struct Lambda
{
void operator()(auto& n) const
{
n = 1;
}
};
int main()
{
auto a = A{};
a.f(Lambda{}); // ok
a.f([](auto& n) { n = 1; }); // error: assignment of read-only reference 'n'
}
See online demo
Why does C++ lambda overloading not behave as expected?
Upvotes: 3
Views: 121
Reputation: 119219
-> void
return type, thus avoiding return type deduction.std::invocable_v
rather than std::invoke_result_t
. However, the code in this case is still ill-formed because return type deduction is still triggered even though you're not asking for it.is_invocable
to determine whether or not the INVOKE expression would be "well-formed when treated as an unevaluated operand". libstdc++ and libc++ both use decltype
to create an unevaluated operand for this purpose, so, obviously, return type deduction has to be done. But it seems to me that there is no way to avoid triggering return type deduction, therefore there is no possible standard library implementation that would allow your code to compile (it is not a bug in GCC/Clang).Upvotes: 4