在 C++20 中使用 lambda 进行参数包扩展

康桓瑋*_*康桓瑋 21 c++ lambda language-lawyer variadic-templates c++20

案例一:

考虑 lambdanoexcept说明符中的以下包扩展:

template <bool... B> 
auto g() {  
  ([]() noexcept(B) {}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

Clang 和 MSVC 接受此代码,但 GCC拒绝:

error: expansion pattern '<lambda>' contains no parameter packs
Run Code Online (Sandbox Code Playgroud)

这是一个有效的代码吗?我应该信任哪个编译器?它看起来像是与PR 47226相关的旧 GCC 错误。

案例2:

考虑 lambda 中的以下包扩展requires-clause:

template <bool... B> 
auto g() {  
  ([](auto) requires(B) {}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Clang 和 MSVC 仍然接受此代码,而 GCC以相同的错误消息拒绝它。这只是同一个错误吗?

案例3:

考虑 lambda 模板列表中的以下包扩展:

template <typename... Args> 
void g(Args...) {
  ([]<Args>(){}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

这次三个编译器都拒绝了相同的错误信息:

expansion pattern '<lambda>' contains no parameter packs
Run Code Online (Sandbox Code Playgroud)

与案例 1相比有什么不同吗?或者这是一个常见的错误?

sig*_*gma 3

有趣的练习!看看 C++20 草案,该标准首先区分了通用 lambda (7.5.5.5):

如果lambda表达式具有任何泛型参数类型占位符 (9.2.8.5),或者 lambda 具有template-parameter-list ,则 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
Run Code Online (Sandbox Code Playgroud)

因此,情况 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>{}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

案例2

template<bool B>
struct closure {
    auto operator()(auto) const requires(B) {}
};

template <bool... B> 
auto g() {  
  (closure<B>{}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

案例3

template<typename T>
struct closure {
    template<T>
    auto operator()() const {}
};

template <typename... Args> 
void g(Args...) {
  (closure<Args>{}, ...);  
}
Run Code Online (Sandbox Code Playgroud)

这些都在我的机器上编译,当前使用 gcc 11.2.1。