This code compiles and executes fine using GCC 13 and Clang 17, but fails to compile on MSVC. I am wondering if the code is required to work according to the standard or if this is a problem with MSVC.
Demo
#include <utility>
#include <iostream>
enum e : int { A=5, B, C, D };
auto x = std::integer_sequence<e, A, B, C, D>{};
auto y = std::integer_sequence<unsigned, 9, 4, 3, 8>{};
auto z = std::integer_sequence<int, 0, 1, 2, 3>{};
template<typename T, T... ints>
void print_sequence(std::integer_sequence<T, ints...> int_seq)
{
std::cout << "The sequence of size " << int_seq.size() << ": ";
((std::cout << ints << ' '), ...);
std::cout << 'n';
}
int main(int, char**)
{
print_sequence(x);
print_sequence(y);
print_sequence(z);
return 0;
}
MSVC gives this error:
error C2338: static_assert failed: ‘integer_sequence<T, I…> requires T to be an integral type.’
2
2 Answers
MSVC-STL and libc++† are right, as e
is not an integral type (i.e. std::is_integral_v<e>
is false
).
From [intseq.intseq]:
namespace std { template<class T, T... I> struct integer_sequence { using value_type = T; static constexpr size_t size() noexcept { return sizeof...(I); } }; }
Mandates:
T
is an integer type.
It is worth noting that, in contrast, integral_constant
has no requirement for T
, so things like integral_constant<pair<int, int>, pair{0, 0}>
are perfectly fine in C++20.
† Clang’s libc++ needs to be enabled through the -stdlib=libc++
flag, and it also has a corresponding static_assert
in the integer_sequence
implementation.
7
-
1
And here's the definition of "integer type", for the curious: eel.is/c++draft/basic.fundamental#11
– HolyBlackCat22 hours ago
-
@HolyBlackCat and again the same defect in std. Instead of such long comments, why don't they constrain std templates? Just put
template <std::integral T>
there: it's self explanatory, and enforcing correct behavior.– Red.Wave20 hours ago
-
1
@n.m.couldbeanAI it is simple to mandate: "STL classes and functions shall be constraint with concepts to reflect th std requirements". And the implementers are supposed to fortify their implementations. A lot of classes already use old SFINAE adhoc; addition of a
requires
clause in theENABLE_IF
macro wouldn't be a big deal.– Red.Wave20 hours ago
-
1
@Red.Wave What is STL? There is no mention of it in the standard (except as a part of the word manifestly). Anyway if you think it is easy, do submit a proposal. Make sure to attend committee meetings to explain it to other committee members and defend it against the inevitable "why do we need that" and "it will probably break backwards compatibility" and whatnot.
– n. m. could be an AI19 hours ago
-
1
@n.m.couldbeanAI if only I could attend the meetings, there was a lot I would mention.
– Red.Wave19 hours ago
Clang and gcc are wrong in accepting the program as e
is not an integer type(static_assert(std::is_integral_v<e>
) will fail) and the first template argument for std::integer_sequence
must be an integer type.
template< class T, T... Ints > class integer_sequence; (since C++14)
Template parameters
T
– an integer type to use for the elements of the sequence
And from integer type
The types char, wchar_t, char8_t, char16_t, and char32_t are collectively called character types.
The character types, bool, the signed and unsigned integer types, and cv-qualified versions ([basic.type.qualifier]) thereof, are collectively termed integral types.
A synonym for integral type is integer type.
You can also check this by using a static_assert:
static_assert(std::is_integral_v<e>); //msvc, gcc and clang all fail this as expected
Workaround
You can use std::underlying_type
:
auto x = std::integer_sequence<std::underlying_type_t<e>, A, B, C, D>{};
Reduced example.
22 hours ago
Side note: You could fall back to
std::integer_sequence<std::underlying_type_t<e>, ...>
.22 hours ago