c++ - 在 C++20 中使用 lambda 进行参数包扩展
问题描述
案例一:
考虑 lambda 说明符中的以下包扩展noexcept
:
template <bool... B>
auto g() {
([]() noexcept(B) {}, ...);
}
Clang 和 MSVC 接受此代码,但 GCC拒绝:
error: expansion pattern '<lambda>' contains no parameter packs
这是一个有效的代码吗?我应该信任哪个编译器?
案例二:
考虑 lambda 中的以下包扩展requires-clause
:
template <bool... B>
auto g() {
([](auto) requires(B) {}, ...);
}
在这种情况下,Clang 和 MSVC 仍然接受此代码,而 GCC以相同的错误消息拒绝它。这只是同一个错误吗?
案例3:
考虑 lambda 模板列表中的以下包扩展:
template <typename... Args>
void g(Args...) {
([]<Args>(){}, ...);
}
这次三个编译器都拒绝了相同的错误消息:
expansion pattern '<lambda>' contains no parameter packs
与案例1相比有区别吗?或者这是一个常见的错误?
更新:
解决方案
有趣的练习!查看 C++20 草案,标准首先区分了泛型 lambdas (7.5.5.5):
如果lambda 表达式具有任何通用参数类型占位符 (9.2.8.5),或者 lambda 具有模板参数列表,则lambda 是通用 lambda。
int i = [](int i, auto a) { return i; }(3, 4); // OK: a generic lambda int j = []<class T>(T t, int i) { return i; }(3, 4); // OK: a generic lambda
因此,案例 1 具有非泛型 lambda,而案例 2 和 3 具有泛型 lambda。它不区分类型和非类型模板参数,所以我认为我同意 Yakk - Adam Nevraumont 的观点,这三个都应该是可以接受的。
Lambda 由一个未命名的唯一闭包类型表示,该闭包类型具有函数调用运算符 ( operator()
)(在泛型 lambda 的情况下为模板),其签名和约束由 lambda 表达式确定。编译器绝对可以使用类似于以下的代码来满足每种情况:
情况1
template<bool B>
struct closure {
auto operator()() const noexcept(B) {}
};
template <bool... B>
auto g() {
(closure<B>{}, ...);
}
案例2
template<bool B>
struct closure {
auto operator()(auto) const requires(B) {}
};
template <bool... B>
auto g() {
(closure<B>{}, ...);
}
案例3
template<typename T>
struct closure {
template<T>
auto operator()() const {}
};
template <typename... Args>
void g(Args...) {
(closure<Args>{}, ...);
}
这些都在我的机器上编译,目前使用 gcc 11.2.1。
推荐阅读
- typescript - *.d.ts 文件有什么用?
- sql-server - 如何解析 MSsql 字符串
- haproxy - 通过从 haproxy 中的列表文件中动态匹配 url 和方法类型来定义 ACL
- spring-tool-suite - STS用java 1.6版本?
- python-3.x - python识别文本中的簇
- sql - SQL server服务重启后等待任务正常down
- python - 带有轴参数的Tensorflow tf.gather
- r - 日志背景渐变ggplot
- java - Android:位置更新在后台一段时间(20-30 分钟)后停止
- javascript - 如果 x = null 则将对象属性分配给值