'Problem with std::index_sequence_for as default argument?
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.
Solution 1:[1]
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();
}
Solution 2:[2]
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...>{} );
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Alex Vask |