简体   繁体   中英

Parameter pack expansion with lambda in C++20

Case 1 :

Consider the following pack expansion in lambda noexcept specifier:

template <bool... B> 
auto g() {  
  ([]() noexcept(B) {}, ...);  
}

Clang and MSVC accept this code, but GCC rejects with:

error: expansion pattern '<lambda>' contains no parameter packs

Is this a valid code? Which Compiler should I trust?

Case 2 :

Consider the following pack expansion in lambda requires-clause :

template <bool... B> 
auto g() {  
  ([](auto) requires(B) {}, ...);  
}

In this case, Clang and MSVC still accept this code, and GCC rejects it with the same error message. Is this just the same bug?

Case 3 :

Consider the following pack expansion in the lambda template list:

template <typename... Args> 
void g(Args...) {
  ([]<Args>(){}, ...);  
}

This time three compiler all reject with the same error message:

expansion pattern '<lambda>' contains no parameter packs

Is there a difference compared to case 1? Or is this a common bug?


Update:

GCC fixed case 1 in 99584 , and MSVC fixed case 3 in this .

Interesting exercise, Looking at the C++20 draft. the standard first distinguishes generic lambdas (7.5.5:5):

A lambda is a generic lambda if the lambda-expression has any generic parameter type placeholders (9.2.8.5), or if the lambda has a template-parameter-list .

 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

Therefore, case 1 has non-generic lambdas and 2 and 3 have generic lambdas. It does not differentiate between type and non-type template parameters, so I think I agree with Yakk - Adam Nevraumont, all three should be admissible.

Lambdas are represented by an unnamed, unique closure type having a function call operator ( operator() ) (template in case of a generic lambda), whose signature and constraints are determined by the lambda expression. The compiler could definitely satisfy each case with code resembling the following:

Case 1

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

template <bool... B> 
auto g() {  
  (closure<B>{}, ...);  
}

Case 2

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

template <bool... B> 
auto g() {  
  (closure<B>{}, ...);  
}

Case 3

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

template <typename... Args> 
void g(Args...) {
  (closure<Args>{}, ...);  
}

These all compile on my machine, currently with gcc 11.2.1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM