4

I'm using C++ with GCC's C extension for designated inits / designated array initializers and I've come across a bit of a pickle. If I have the following (contrived) example code,

#include <string>
#include <string_view>

struct STRUCTURE {
    enum class ENUM { A, B, C };
    static constexpr std::string_view STRINGS[] {
        [static_cast<int>(ENUM::A)] = "A",
        [static_cast<int>(ENUM::B)] = "B",
        [static_cast<int>(ENUM::C)] = "C"
    };

    constexpr std::string_view operator[](ENUM e) const {
        return STRINGS[static_cast<int>(e)];
    }
};

Everything works as expected. However, if I now template the structure, i.e.

#include <string>
#include <string_view>

template <typename T>
struct STRUCTURE { /*same structure definition*/ };

I get a compile-time error that the C99 designator initializers I have are not integral constant expressions.

In fact, in some cases with namespaces I get an internal compiler error / internal compiler segfault, leading me to believe this is an internal issue, but I cannot confirm such.

If I move the scoped enum class outside of the template, everything works again. In that manner, I can simply add a level of indirection to my actual code, however I would prefer not doing so.

Here is a godbolt with a macro allowing you to change between the templated and non-templated definition, and a simple main printing out one of the strings.

Even odder: Say I change the type of the internal array to ints. I.e,

struct STRUCTURE {
    enum class ENUM { A, B, C };
    static constexpr int INTS[] {
        [static_cast<int>(ENUM::A)] = 65,
        [static_cast<int>(ENUM::B)] = 66,
        [static_cast<int>(ENUM::C)] = 67
    };

    constexpr int operator[](ENUM e) const {
        return INTS[static_cast<int>(e)];
    }
};

I have the same issue. But now if I assign the values via static casts of the enum as the designators are, i.e,

...
    static constexpr int INTS[] {
        [static_cast<int>(ENUM::A)] = static_cast<int>(ENUM::A),
        [static_cast<int>(ENUM::B)] = static_cast<int>(ENUM::B),
        [static_cast<int>(ENUM::C)] = static_cast<int>(ENUM::C)
    };
...

This works, template or not. Godbolt for this, too.

13steinj
  • 418
  • 5
  • 12
  • 1
    I know fully well this is not standard C++, as I mentioned in the first sentence. The extension I listed is commonly used. My question is about the inconsistency between the templated and non-templated version, as the extension I am using does not change whether or not using the inner enum is a constant expression or not. – 13steinj Jan 16 '21 at 18:31
  • 2
    `This extension is not implemented in GNU C++. ` – KamilCuk Jan 16 '21 at 18:35
  • what is your question actually? I mean it is interesting, but you already know that it is not standard C++, you know what is fine with gcc and what not, what now? – 463035818_is_not_an_ai Jan 16 '21 at 18:41
  • @KamilCuk this appears to be a misnomer. As mentioned on the main GNU C extension page it states: "These extensions are available in C and Objective-C. Most of them are also available in C++. See Extensions to the C++ Language, for extensions that apply only to C++. Some features that are in ISO C99 but not C90 or C++ are also, as extensions, accepted by GCC in C90 mode and in C++." This extension is indeed accepted in C++. – 13steinj Jan 16 '21 at 18:42
  • @largest_prime_is_463035818 My question, as literally stated, is it appears as though the compiler rejects static casts of scoped enums of templates as constant expressions, but only in some cases. This is one such case. But as far as I know, being a member of a template does not strip it of constant-expression status. I can't tell if this is a bug, or if it is intended behavior. Which is it? I'm not familiar enough with gcc to say. – 13steinj Jan 16 '21 at 18:44
  • 1
    `I can't tell if this is a bug, or if it is intended behavior. Which is it?` I believe a way better place to ask that would be to ask gcc developers. Go to gcc mailing list and ask them. If you found "internal error" or gcc segfaulted, make sure it's reproducible and that's (almost) for sure a bug. – KamilCuk Jan 16 '21 at 18:52
  • @KamilCuk perfectly valid point, and that was my next step. But the point of stackoverflow is to ask such questions, and it could very well be that I'm merely missing some name-resolution subtlety such that when templated, I should be resolving the enumeration differently, which is why I asked here first. – 13steinj Jan 16 '21 at 18:56
  • Looks like an easy workaround is to move the inner enum outside of the class. (on the other hand, you can also do a `static_assert` that the enum values are consecutive in that order, then fill into the array manually) – user202729 Jan 17 '21 at 06:58
  • @user202729 yes, I mentioned that workaround in my question, just that it was inadequate for my use case (style guide, go figure). Can you elaborate on that `static_assert` bit? – 13steinj Jan 18 '21 at 06:24

0 Answers0