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


#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重载的行为不符合预期?

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

最新更新