C++20 constexpr 向量和字符串不起作用
C++20 constexpr vector and string not working
我在尝试创建 constexpr
std::string
和 std::vector
对象时遇到奇怪的编译器错误:
#include <vector>
#include <string>
int main()
{
constexpr std::string cs{ "hello" };
constexpr std::vector cv{ 1, 2, 3 };
return 0;
}
编译器抱怨“表达式必须有常量值”:
我错过了什么吗?我使用的是最新的 Microsoft Visual Studio 2019 版本:16.11.4,参考文献 (https://en.cppreference.com/w/cpp/compiler_support) 指出此编译器版本支持 constexpr
字符串和向量:
我也试过 constexpr std::array
,确实有效。该问题可能与与向量相关的动态内存分配有关吗?
您的程序实际上格式错误,尽管错误可能难以理解。 constexpr
C++20 中的分配支持是有限的 - 你只能有 transient 分配。也就是说,分配必须在常量评估结束时完全解除分配。
所以你不能这样写:
int main() {
constexpr std::vector<int> v = {1, 2, 3};
}
因为 v
的分配持续存在 - 它是非暂时性的。这就是错误告诉您的内容:
<source>(6): error C2131: expression did not evaluate to a constant
<source>(6): note: (sub-)object points to memory which was heap allocated during constant evaluation
v
不能常量,因为它还在坚持堆分配,不允许这样做。
但是你可以写this:
constexpr int f() {
std::vector<int> v = {1, 2, 3};
return v.size();
}
static_assert(f() == 3);
此处,v
的分配是暂时的——内存在 f()
returns 时被释放。但是我们仍然可以在 constexpr
时间内使用 std::vector
。
正如@barry 所解释的,您不能创建需要动态分配并且在运行时仍然可用的变量。我相信这可以通过以下排除来解释:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
https://eel.is/c++draft/expr.const#5.17
a new-expression ([expr.new]), unless the selected allocation function is a replaceable global allocation function ([new.delete.single], [new.delete.array]) and the allocated storage is deallocated within the evaluation of E;
您仍然可以使用这些新功能做出令人惊奇的事情。例如连接字符串:
constexpr std::string join(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;
});
return result;
}
static_assert(join({ "one", "two", "three" }, ';') == "one;two;three"sv);
我在尝试创建 constexpr
std::string
和 std::vector
对象时遇到奇怪的编译器错误:
#include <vector>
#include <string>
int main()
{
constexpr std::string cs{ "hello" };
constexpr std::vector cv{ 1, 2, 3 };
return 0;
}
编译器抱怨“表达式必须有常量值”:
我错过了什么吗?我使用的是最新的 Microsoft Visual Studio 2019 版本:16.11.4,参考文献 (https://en.cppreference.com/w/cpp/compiler_support) 指出此编译器版本支持 constexpr
字符串和向量:
我也试过 constexpr std::array
,确实有效。该问题可能与与向量相关的动态内存分配有关吗?
您的程序实际上格式错误,尽管错误可能难以理解。 constexpr
C++20 中的分配支持是有限的 - 你只能有 transient 分配。也就是说,分配必须在常量评估结束时完全解除分配。
所以你不能这样写:
int main() {
constexpr std::vector<int> v = {1, 2, 3};
}
因为 v
的分配持续存在 - 它是非暂时性的。这就是错误告诉您的内容:
<source>(6): error C2131: expression did not evaluate to a constant
<source>(6): note: (sub-)object points to memory which was heap allocated during constant evaluation
v
不能常量,因为它还在坚持堆分配,不允许这样做。
但是你可以写this:
constexpr int f() {
std::vector<int> v = {1, 2, 3};
return v.size();
}
static_assert(f() == 3);
此处,v
的分配是暂时的——内存在 f()
returns 时被释放。但是我们仍然可以在 constexpr
时间内使用 std::vector
。
正如@barry 所解释的,您不能创建需要动态分配并且在运行时仍然可用的变量。我相信这可以通过以下排除来解释:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
https://eel.is/c++draft/expr.const#5.17
a new-expression ([expr.new]), unless the selected allocation function is a replaceable global allocation function ([new.delete.single], [new.delete.array]) and the allocated storage is deallocated within the evaluation of E;
您仍然可以使用这些新功能做出令人惊奇的事情。例如连接字符串:
constexpr std::string join(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;
});
return result;
}
static_assert(join({ "one", "two", "three" }, ';') == "one;two;three"sv);