如何将字符串列表存储在 constexpr 上下文中?

How can a list of strings be stored in a constexpr context?

我正在为某个域对象 类 转换这些文档字符串表(作为系统的类型特征),直到我偶然发现了这个问题。 后来,我打算在编译时检查这些特殊成员是否编写了文档(作为我在编译时喜欢它的原因)。 我创建了一个小例子来演示:

https://godbolt.org/z/3dX3-e

#include <initializer_list>

struct CStr {
    struct M {
      const char* name;
      const char* val;
    };

  constexpr CStr(const std::initializer_list<M>& str) : str_(str) {
  };

  std::initializer_list<M> str_;
};

constexpr CStr cstr_test{ { {"key", "val"} } };

int main() {
  return cstr_test.str_.begin()->name[0];
}

基本上 3 个主要编译器似乎以不同的方式处理这种情况,似乎 也适用于较旧的 , but fails to compile when changed to latest version 9.1 (saying the cstr_test line is not a contant expression). On (and the one im interested in) the initializer_list gets the size correct but the temporary does not survive to the output. refused to compile, due to a temporary being created. This last thing seems like a hint, and Im suspecting this is what could be happening with 但没有发出错误。

如果将 std::initializer_list<M> 更改为仅 M,则示例可以修复。

参考文献中的相关部分可能是:

The underlying array is a temporary array of type const T[N], in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list. The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.

如何在编译时创建包含字符串的对象列表?

std::initializer_list 不应用作存储。

所以在您的情况下,存储应该在 class 之外完成。可以使用常规 C-array 或 std::array

那么您 class 可能只查看该数据。

C++20 提供 std::span.

在 C++20 之前,您可能会这样做:

struct CStr {
    struct M {
        const char* name;
        const char* val;
    };

    constexpr CStr(const M* data, std::size_t size) : data(data), size(size) {}

    const M* begin() const { return data; }
    const M* end() const { return data + size; }

    const M* data;
    std::size_t size;
};

 constexpr CStr::M data[]{ { {"key", "val"} } };

 constexpr CStr cstr_test(data, 1);

int main() {
  return cstr_test.begin()->name[0];
}

它的方法有点不同(IMO 你的例子太复杂了),但是 C++17 引入了 std::string_view 所以这可以用简单的方式处理而无需额外的 类。此外,当您不知道有多少元素时,您可以使用 C-like array:

const constexpr std::pair<std::string_view, std::string_view> str_test[] {
    { "a"sv, "alpha"sv },
    { "b"sv, "beta"sv },
    { "c"sv, "siera"sv },
};

现场演示 gcc clang msvc.