Are enum values allowed in a std::integer_sequence?

Are enum values allowed in a std::integer_sequence?


14

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.’

New contributor

jtl313 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

2

2 Answers
2


13

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

    – HolyBlackCat

    22 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.Wave

    20 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 the ENABLE_IF macro wouldn't be a big deal.

    – Red.Wave

    20 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 AI

    19 hours ago

  • 1

    @n.m.couldbeanAI if only I could attend the meetings, there was a lot I would mention.

    – Red.Wave

    19 hours ago


10

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.

From std::integer_sequence

template< class T, T... Ints >
class integer_sequence;   (since C++14)

Template parameters
Tan 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>{};

Demo with std::underlying_type_t



Leave a Reply

Your email address will not be published. Required fields are marked *