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

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

查看在线演示

C++的lambda重载为什么不会按照预期运行?


似乎由于某种原因,重载决议希望它成为“const”函数,并且“auto&”被推导为“int const&”,尽管值已更改。将其更改为“int&”可以解决问题,但仍然很奇怪,特别是上面的行可以正常工作。使用概念可以避免这种情况。 - Lala5th
1个回答

4
  1. 你的问题与Hard error when using std::invoke_result_t with a generic lambda几乎相同。与另一个问题一样,如果更改lambda使其具有显式的-> void返回类型,从而避免返回类型推断,您的代码将按您预期的方式工作。
  2. 您的问题与其他问题的区别在于,您正在使用std::invocable_v而不是std::invoke_result_t。然而,在这种情况下,代码仍然不正确,因为即使您不要求,返回类型推断仍然会触发。
  3. 标准要求is_invocable确定当被视为未评估操作数时“INVOKE”表达式是否“良好形成”。libstdc++和libc++都使用decltype为此创建未评估操作数,因此必须进行返回类型推断。但是,我认为没有办法避免触发返回类型推断,因此没有可能的标准库实现可以使您的代码编译(这不是GCC / Clang的错误)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接