Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with std::index_sequence_for as default argument?

Tags:

c++

c++20

The following C++20 program:

#include <utility>
#include <cstddef>

template<typename... Args>
class C {
    template<size_t... I>
    static void call(
      std::index_sequence<I...> = std::index_sequence_for<Args...>{}
    ) {}
};

int main() {
    C<long int>::call();
}

fails to compile with error message:

test.cc: In static member function ‘static void C<Args>::call(std::index_sequence<I ...>) [with long unsigned int ...I = {}; Args = {long int}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int>]’:
test.cc:11:20: error: could not convert ‘std::index_sequence_for<long int>{}’ from ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’ to ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’
   11 |  C<long int>::call();
      |                    ^
      |                    |
      |                    integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>
test.cc:11:20: note:   when instantiating default argument for call to ‘static void C<Args>::call(std::index_sequence<I ...>) [with long unsigned int ...I = {}; Args = {long int}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int>]’
test.cc: In function ‘int main()’:
test.cc:11:20: error: could not convert ‘std::index_sequence_for<long int>{}’ from ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’ to ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’

Any ideas?

Update:

My current best workaround is to factor out default argument into two functions like:

template<typename... Args>
class C {
    static void call() {
      _call(std::index_sequence_for<Args...>{});
    }

    template<size_t... I>
    static void _call(std::index_sequence<I...>) {}
};

This seems to work around compiler bug (if that's what it is).

Update 2:

The below program fails for the same reason the original one does:

template<typename T> void f(T x = 42) {}

int main() { f(); }

so it's a feature not a bug.

like image 355
Andrew Tomazos Avatar asked Mar 13 '26 23:03

Andrew Tomazos


2 Answers

In general template argument deduction + default function arguments cause a lot of trouble. To simply fix it you can go with this:

#include <utility>
#include <cstddef>

template<typename... Args>
class C {
public:
    static void call() {
        call_impl(std::index_sequence_for<Args...>{});
    }

private:
    template<size_t... I>
    static void call_impl(std::index_sequence<I...> ) {
    }
};

int main() {
    C<long int>::call();
}
like image 200
bartop Avatar answered Mar 16 '26 13:03

bartop


In C++20 you can also write a templated lambda to do exactly that without creating a new function:

//...
static void call() {
    return [&]<size_t... Is>(std::index_sequence<Is...>) {
        /* your code goes here... */ 
    }( std::index_sequence_for<Args...>{} );
}
like image 27
Alex Vask Avatar answered Mar 16 '26 12:03

Alex Vask



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!