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

时间:2019-05-16 08:37:04

标签: c++ language-lawyer c++17 constexpr initializer-list

我一直在为某些域对象类转换这些docstring表(作为系统的类型特征),直到我遇到这个问题为止。 后来,我打算在编译时检查这些特殊成员是否编写了文档(作为为什么在编译时我想要它的原因)。 我创建了一个小示例进行演示:

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>更改为M,则示例可以固定。

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

  

基础数组是类型为const T [N]的临时数组,其中   每个元素均已复制初始化(缩小转换范围除外)   是无效的)   初始化列表。基础数组的生存期与   任何其他临时对象,除了初始化   数组中的initializer_list对象延长了   数组完全类似于将引用绑定到临时(具有相同的   异常,例如用于初始化非静态类成员的异常)。的   基础数组可以分配在只读内存中。

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:-1)

它的方法有些不同(IMO,您的示例过于复杂),但是C ++ 17引入了std::string_view,因此可以通过简单的方式来处理它,而无需额外的类。另外,当您不知道有多少个元素时,可以使用类似C的数组:

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