xmllmx
xmllmx

Reputation: 42371

Why does C++ lambda overloading not behave as expected?

#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

Answers (1)

Brian Bi
Brian Bi

Reputation: 119219

  1. Your question is nearly a duplicate of Hard error when using std::invoke_result_t with a generic lambda . As with the other question, your code will work the way you expect, if you change the lambda so that it has an explicit -> void return type, thus avoiding return type deduction.
  2. The difference between your question and the other one is that in your question, you're using 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.
  3. The standard requires 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

Related Questions