首页 > 解决方案 > 如何将字符串列表存储在 constexpr 上下文中?

问题描述

我正在为某些域对象类转换这些文档字符串表(作为像系统这样的类型特征),直到我偶然发现这个问题。后来,我计划在编译时检查这些特殊成员是否编写了文档(作为我为什么在编译时想要它的理由)。我创建了一个小示例进行演示:

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 个主要编译器似乎对这种情况有不同的处理方式,这似乎适用于较旧的,但在更改为最新版本 9.1 时无法编译(说 cstr_test 行不是一个常量表达式)。在和我感兴趣的那个)上initializer_list,大小正确,但临时文件无法保存到输出。拒绝编译,因为临时创建了。可能发生的事情,但没有发出错误。

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

参考资料中的相关部分可能是:

底层数组是一个 const T[N] 类型的临时数组,其中每个元素都是从原始初始化列表的相应元素复制初始化的(除了缩小转换无效)。底层数组的生命周期与任何其他临时对象相同,只是从数组初始化一个 initializer_list 对象可以延长数组的生命周期,就像将引用绑定到临时对象一样(有相同的例外,例如初始化非-静态类成员)。底层数组可以分配在只读存储器中。

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

标签: c++language-lawyerc++17constexprinitializer-list

解决方案


std::initializer_list不应该用作存储。

因此,在您的情况下,应该在课堂之外进行存储。常规 C 数组或std::array可用于此。

然后你的班级可能只看到这些数据。

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];
}

推荐阅读