C++20 中的 constexpr std::string 如何工作?

dig*_*evo 30 c++ stdstring constexpr c++20

显然,constexpr std::string尚未添加到GCClibstdc++中(从 GCC v11.2 开始)。

这段代码:

#include <iostream>
#include <string>

int main()
{
    constexpr std::string str { "Where is the constexpr std::string support?"};

    std::cout << str << '\n';
}
Run Code Online (Sandbox Code Playgroud)

不编译:

#include <iostream>
#include <string>

int main()
{
    constexpr std::string str { "Where is the constexpr std::string support?"};

    std::cout << str << '\n';
}
Run Code Online (Sandbox Code Playgroud)

char当字符串包含超过 16秒(因为 GCC 的 SSO 缓冲区大小为 16)时,此类字符串将如何工作?简短的解释是什么?一个简单的构造函数会在堆栈上创建字符串对象并且从不使用动态分配吗?

这段代码:

    std::cout << "is_trivially_constructible: "
              << std::boolalpha << std::is_trivially_constructible<const std::string>::value << '\n';
Run Code Online (Sandbox Code Playgroud)

打印这个:

is_trivially_constructible: false
Run Code Online (Sandbox Code Playgroud)

现在通过这里使用constexpr(显然不能用 GCC v11.2 编译):

    std::cout << "is_trivially_constructible: "
              << std::boolalpha << std::is_trivially_constructible<constexpr std::string>::value << '\n';
Run Code Online (Sandbox Code Playgroud)

结果会true像下面这样吗?

is_trivially_constructible: true
Run Code Online (Sandbox Code Playgroud)

我的目标

我的目标是做类似的事情:

    constexpr std::size_t a { 4 };
    constexpr std::size_t b { 5 };
    constexpr std::string msg { std::format( "{0} + {1} == {2}", a, b, a + b ) };

    std::cout << msg << '\n';
Run Code Online (Sandbox Code Playgroud)

也不在 GCC v11.2 上编译std::formatconstexpr std::string

Bar*_*rry 44

C++20 支持在 constexpr 时间内分配,只要在时间常量求值结束时完全释放分配即可。例如,这个非常愚蠢的例子在 C++20 中是有效的:

constexpr int f() {
    int* p = new int(42);
    int v = *p;
    delete p;
    return v;
}

static_assert(f() == 42);
Run Code Online (Sandbox Code Playgroud)

但是,如果您忘记delete p;了,那么 thenf()就不再是常量表达式。不能泄漏内存。例如,gcc 拒绝:

<source>:2:24: error: '(f() == 42)' is not a constant expression because allocated storage has not been deallocated
    2 |     int* p = new int(42);
      |                        ^
Run Code Online (Sandbox Code Playgroud)

回到你的问题,对于长字符串来说std::string效果constexpr很好——通过按照你的预期为其分配内存。然而,C++20 constexpr 规则仍然受到此规则的限制,即所有分配必须在评估结束时清理。换句话说,所有分配都必须是瞬态的- C++ 尚不支持非瞬态 constexpr 分配。

结果,你原来的程序

int main( )
{
    constexpr std::string str { "Where is the constexpr std::string support?"};
}
Run Code Online (Sandbox Code Playgroud)

是无效的,即使 gcc 支持constexpr string(就像现在在 trunk 上所做的那样),因为str需要被销毁。但这就好了:

constexpr int f() {
    std::string s = "Where is the constexpr std::string support?";
    return s.size();
}

static_assert(f() > 16);
Run Code Online (Sandbox Code Playgroud)

而它不会在 C++17 中编译。


C++23 中仍然不支持非瞬态 constexpr 分配。这是一个令人惊讶的棘手问题。但是,希望很快。