c++ 20朝着在编译时使用std::string迈进了一步,但是P0980将不允许你编写像你的问题中的代码:
constexpr std::string constString = "constString";
the reason is that constexpr std::string is allowed only to be used in constexpr function (constant expression evaluation context). Memory allocated by constexpr std::string must be freed before such function returns - this is the so called transient allocation, and this memory cannot 'leak' outside to runtime to constexpr objects (stored in data segments) accessible at runtime . For example compilation of above line of code in current VS2022 preview (cl version : 19.30.30704) results in following error:
1> : error C2131: expression did not evaluate to a constant
1> : message : (sub-)object points to memory which was heap allocated during constant evaluation
这是因为它试图进行不允许的非瞬态分配——这将意味着分配到已编译二进制文件的数据段中。
在p0784r1中,在“非瞬态分配”段落中,你可以发现有一个计划允许将瞬态内存转换为静态内存(强调我的):
在时间计算时还没有释放的存储怎么办
完成吗?我们可以不允许,但确实有
这可能是可取的令人信服的用例。例如,这可能
作为更灵活的“字符串字面值”类的基础。我们
因此,提出如果非瞬态constexpr分配为
有效的(下面将进行描述),则将分配的对象提升为
静态存储持续时间。
有一种方法可以将暂态std::string数据导出到外部,使其在运行时可用。你必须复制它到std::array,问题是计算std::array的最终大小,你可以预设一些大的大小或计算std::string两次-一次得到大小,然后得到atual数据。以下代码成功编译并在当前VS2022预览5上运行。它基本上是用分隔符连接三个单词:
constexpr auto join_length(const std::vector<std::string>& vec, char delimiter) {
std::size_t length = std::accumulate(vec.begin(), vec.end(), 0,
[](std::size_t sum, const std::string& s) {
return sum + s.size();
});
return length + vec.size();
}
template<size_t N>
constexpr std::array<char, N+1> join_to_array(const std::vector<std::string>& vec, char delimiter) {
std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
vec[0],
[&delimiter](const std::string& a, const std::string& b) {
return a + delimiter + b;
});
std::array<char, N+1> arr = {};
int i = 0;
for (auto c : result) {
arr[i++] = c;
}
return arr;
}
constexpr std::vector<std::string> getWords() {
return { "one", "two", "three" };
}
int main()
{
constexpr auto arr2 = join_to_array<join_length(getWords(), ';')>(getWords(), ';');
static_assert(std::string(&arr2[0]) == "one;two;three");
std::cout << &arr2[0] << "\n";
}