You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20:requires子句中使用立即调用lambda为何遭编译器拒绝?

为何三款编译器均拒绝调用f2?C++20 requires子句中使用立即调用lambda是否违反标准?

问题代码

// 注意:`g`的函数体与`f2`的requires子句中的lambda体完全相同

constexpr auto g(auto b) {
    using c1 = decltype([](int){ return true; });
    using c2 = decltype([](bool){ return true; });
    struct v : c1, c2 { using c1::operator(), c2::operator(); };
    return v{}(decltype(b){});
}
auto f1(auto a) requires (g(decltype(a){})) {}
auto f2(auto a) requires ([](auto b) {
    using c1 = decltype([](int){ return true; });
    using c2 = decltype([](bool){ return true; });
    struct v : c1, c2 { using c1::operator(), c2::operator(); };
    return v{}(decltype(b){});
}(decltype(a){})) {}

auto m() {
    f1(true); // 所有编译器均通过
    f2(true); // 所有编译器均拒绝
}

编译器错误信息

Clang错误输出

<source>:12:5: error: 找不到匹配的'f2'调用
   12 |     f2(true);
      |     ^~
<source>:9:6: note: 候选模板被忽略:约束未满足
[with a:auto = bool]
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |      ^
<source>:9:27: note: 原因是替换后的约束表达式格式错误:
找不到匹配的函数
用于调用类型为'(lambda at <source>:9:27)'的对象
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                           ^

GCC错误输出

<source>: 在'struct<lambda(auto:4)>::v'的实例化中:
<source>:9:39:   要求来自'<lambda(auto:4)> [with auto:4 = bool]'
    4 |     struct v : c1, c2 { using c1::operator(), c2::operator(); }; \
      |                                                               ^
<source>:9:45:   由'template<class auto:3> auto f2(auto:3) requires (<lambda>)({}) [with auto:3 = bool]'的替换所要求
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                          ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
<source>:12:7:   要求来自此处
   12 |     f2(true);
      |     ~~^~~~~~
<source>:4:44: error: 类型'<lambda(auto:4)>::v::<lambda(int)>'不是'<lambda(auto:4)>::v'的基类型
    4 |     struct v : c1, c2 { using c1::operator(), c2::operator(); }; \
      |                                            ^
<source>:9:39: note: 在宏'body'的展开中
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                                       ^~~~
<source>:4:60: error: 类型'<lambda(auto:4)>::v::<lambda(bool)>'不是'<lambda(auto:4)>::v'的基类型
    4 |     struct v : c1, c2 { using c1::operator(), c2::operator(); }; \
      |                                                            ^
<source>:9:39: note: 在宏'body'的展开中
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                                       ^~~~
<source>: 在'<lambda(auto:4)> [with auto:4 = bool]'的实例化中:
<source>:9:45:   由'template<class auto:3> auto f2(auto:3) requires (<lambda>)({}) [with auto:3 = bool]'的替换所要求
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                          ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
<source>:12:7:   要求来自此处
   12 |     f2(true);
      |     ~~^~~~~~
<source>:5:15: error: 对成员'operator()'的请求不明确
    5 |     return v{}(decltype(b){});
      |            ~~~^~~~~~~~~~~~~~~
<source>:9:39: note: 在宏'body'的展开中
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                                       ^~~~
<source>:3:25: note: 候选者为:'<lambda(auto:4)>::<lambda(bool)>'
    3 |     using c2 = decltype([](bool){ return true; }); \
      |                         ^
<source>:9:39: note: 在宏'body'的展开中
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                                       ^~~~
<source>:2:25: note:                 '<lambda(auto:4)>::<lambda(int)>'
    2 |     using c1 = decltype([](int){ return true; }); \
      |                         ^
<source>:9:39: note: 在宏'body'的展开中
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |                                       ^~~~
<source>: 在函数'auto m()'中:
<source>:12:7: error: 找不到匹配的'f2(bool)'调用
   12 |     f2(true);
      |     ~~^~~~~~
<source>:9:6: note: 候选者:'template<class auto:3> auto f2(auto:3) requires (<lambda>)({})'
    9 | auto f2(auto a) requires ([](auto b){ body }(decltype(a){})){}
      |      ^~
<source>:9:6: note:   推导的模板参数替换导致上述错误

原因分析与结论

核心问题

代码逻辑上f1和f2的约束判断逻辑完全一致,但f2被拒绝的原因在于:
当在requires子句的立即调用泛型lambda内部定义本地类型v,并继承该lambda内部的嵌套无捕获闭包类型(c1、c2),同时用using声明引入基类的operator()时,编译器在模板参数替换过程中无法正确解析嵌套闭包类型的作用域,导致using声明失效——编译器错误地将闭包类型的operator()视为v的内部成员而非基类成员,最终使得v{}(...)的调用找不到匹配的重载,约束表达式求值失败。

是否违反标准?

不违反C++20标准规则:

  1. C++20允许在requires子句中使用立即调用lambda表达式,约束表达式本身支持这种形式;
  2. 无捕获的闭包类型可以作为基类使用;
  3. 常量表达式上下文允许定义本地类型并进行继承、重载引入等操作。

三款编译器均拒绝f2属于实现层面的缺陷,而非代码违反标准。

内容的提问来源于stack exchange,提问作者303

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:29:50