Explicit instantiation of templated lambda

Viewed 191

I just came across a problem to explicit instantiate a templated lambda. The below code does not compile, but I can't figure out what's wrong in this case:

        [&]<auto... II>(std::index_sequence<II...>) {
            auto check = [&]<auto I>(){
            };
            (check<II>(),...);
        }(std::make_index_sequence<N>{});

Compiler error (gcc trunk: 11.0.0):

rswitch.cc: In lambda function:
rswitch.cc:42:28: error: expected primary-expression before ')' token
42 |                 (check<II>(),...);
|                            ^
rswitch.cc:42:26: error: binary expression in operand of fold-expression
42 |                 (check<II>(),...);

I looks like I had to use the template disambiguation like this:

        [&]<auto... II>(std::index_sequence<II...>) {
            auto check = [&]<auto I>(){
            };
            (this->template check<II>(),...);
        }(std::make_index_sequence<N>{});

Are there other ways to express this?

1 Answers

check itself is not a template. It is an object, of an unspecified closure type, that contains

template<auto I> void operator()();

The member function is the template.

The error is due to the attempt at supplying template arguments to check. Which is not a template itself, again. The template parameters of a lambda's function call operator need to be deducible (even if they are named), for the function call syntax to work. That hasn't changed with C++20.

The only way to specify the parameters explicitly is the pretty ugly

check.template operator()<II>()

But instead it may be better to make it deducible.

[&]<auto... II>(std::index_sequence<II...>) {
    auto check = [&]<auto I>(std::integral_constant<decltype(I), I>){
    };
    (check(std::integral_constant<decltype(II), II>{}),...);
}(std::make_index_sequence<N>{});

Specifying size_t explicitly is also an option instead of using decltype(I).

Related