为什么 C++ lambda 重载的行为不如预期?

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'
}

online demo

为什么 C++ lambda 重载的行为不如预期?

  1. 您的问题几乎与 重复。与另一个问题一样,如果您更改 lambda 以使其具有显式 -> void return 类型,从而避免 return 类型推导,您的代码将按您期望的方式工作。
  2. 你的问题与另一个问题的区别在于,在你的问题中,你使用的是 std::invocable_v 而不是 std::invoke_result_t。然而,这种情况下的代码仍然是错误的,因为 return 类型推导仍然被触发,即使你没有要求它。
  3. 该标准要求 is_invocable 确定 INVOKE 表达式是否“在被视为未计算的操作数时格式正确”。为此,libstdc++ 和 libc++ 都使用 decltype 创建未计算的操作数,因此,显然,必须进行 return 类型推导。但在我看来 ,因此没有可能允许您的代码编译的标准库实现(这不是 GCC/Clang 中的错误)。