【问题标题】:Why does C++ lambda overloading not behave as expected?为什么 C++ lambda 重载的行为不符合预期?
【发布时间】:2021-10-17 01:25:37
【问题描述】:
#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 重载的行为不符合预期?

【问题讨论】:

  • 似乎由于某种原因,重载决议希望它成为const 函数,而auto&amp; 被推导出为int const&amp;,尽管值发生了变化。将其更改为int&amp; 可以修复它,但仍然很奇怪,尤其是在上面的行中。有了概念就可以避免这种情况

标签: c++ lambda overloading standards c++20


【解决方案1】:
  1. 您的问题几乎与Hard error when using std::invoke_result_t with a generic lambda 重复。与另一个问题一样,如果您更改 lambda 以使其具有显式的 -&gt; void 返回类型,那么您的代码将按照您期望的方式运行,从而避免返回类型推导。
  2. 您的问题与另一个问题之间的区别在于,在您的问题中,您使用的是std::invocable_v 而不是std::invoke_result_t。但是,这种情况下的代码仍然是格式错误的,因为即使您没有要求,仍然会触发返回类型推导。
  3. 该标准要求is_invocable 确定INVOKE 表达式是否“在被视为未计算的操作数时格式正确”。 libstdc++ 和 libc++ 都使用decltype 来为此目的创建一个未计算的操作数,因此显然必须进行返回类型推导。但在我看来,there is no way to avoid triggering return type deduction,因此没有可能的标准库实现可以让您的代码编译(这不是 GCC/Clang 中的错误)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多