const 有效但不 constexpr

const works but does not constexpr

这是一个让我挠头的问题,但它适用于 const,但不适用于 constexpr,我想知道你们这些聪明的人是否可以解释一下。用 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()];
 ...

这可以编译,据我所知,它是正确的。如果我改成

constexpr Service namedServices[] =

我明白了

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

这看起来很奇怪,但也许是有充分理由的。或者,它会在 c++20 中修复。

谢谢

namedServices 不是 LiteralType,因为它是包含 std::string 的 class 数组,这不是 LiteralType。因此它不能是 constexpr.

请注意,您的 thcnt() 函数实际上会导致未定义的行为,不需要诊断,因为它没有由于 namedServices 没有持续评估而导致持续评估的情况;并且 std::string strs[thcnt()]; 仅在您启用了 VLA 时才会通过,而 g++ 默认情况下会启用。使用 -pedantic 获得 ISO 一致性。

从 C++20 开始,将有 consteval specifier to cause a compilation error instead of UB NDR, this is supported by clang trunk (example) .


我看到一些建议 C++20 将具有 constexpr std::string 但是 clang 主干(至少是 godbolt 版本)目前不支持它,并且 C++20 还没有完全确定。可能是你的代码在 C++20 中变得合法了。

在此期间,您可以使用 constexpr Service namedServices[] 和:

使代码合法
  • 在 C++14 或更高版本中,通过使用 const char *name;
  • 在 C++17 中,通过使用 std::string_view name;