const works but does not constexpr

Viewed 76

This a scratching my head question, but it works, with const, but not constexpr and I'm wondering if you smart folks can explain. Compiled with g++ -std=c++14.

struct Service
{
    std::string name;
    enum {
        thread,
        interrupt,
        end_types
    } que_type;
};

const Service namedServices[] =
{
    {"abc", Service::thread},
    {"efg", Service::thread},
    {"hij", Service::interrupt},
    {"klm", Service::thread},
    {"nop", Service::interrupt},
    {"qrs", Service::thread},
    {"", Service::end_types}
};

constexpr int thcnt()
{
    int cnt = 0;
    for (const Service* sp = namedServices; sp->que_type != Service::end_types; sp++) {
        if (sp->que_type == Service::thread)
            cnt++;
    }
    return cnt;
}
int main(int argc, char** argv)
{
    std::string strs[thcnt()];
 ...

This compiles and as far as I can tell does the right thing. If I change to

constexpr Service namedServices[] =

I get

... error: the type 'const Service []' of constexpr variable 'namedServices' is not literal
 };
 ^

This seems weird, but perhaps there is a good reason. Or maybe, it will be fixed in c++20.

thanks

1 Answers

namedServices is not a LiteralType since it's an array of class containing std::string which is not a LiteralType. Therefore it cannot be constexpr.

Note that your thcnt() function actually causes undefined behaviour with no diagnostic required, because it has no cases of constant evaluation due to namedServices not having constant evaluation; and std::string strs[thcnt()]; only passes if you have VLAs enabled which g++ does by default. Use -pedantic to get ISO conformance.

As of C++20 there will be consteval specifier to cause a compilation error instead of UB NDR, this is supported by clang trunk (example) .


I have seen some suggestion that C++20 will have constexpr std::string however clang trunk (godbolt edition, at least) currently does not support that, and C++20 has not quite been finalized yet. It may be that your code becomes legal in C++20.

In the meantime you can make the code legal by using constexpr Service namedServices[] and:

  • In C++14 or later, by using const char *name;
  • In C++17, by using std::string_view name;
Related