You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以标准方式保存constexpr std::string函数的返回结果?

编译期生成枚举字符串并复用缓冲区的问题

C++允许constexpr函数返回std::string,比如我们可以借助magic_enum库实现一个生成所有枚举值空格分隔字符串的函数:

template <typename E>
static constexpr std::string GetAllEnumNamesAsString()
{
    const std::string space = " ";
    constexpr std::array names = magic_enum::enum_names<E>();
    std::string all{ names[0] };
    for (int i = 1; i < names.size(); i++)
        all += (space + std::string{ names[i] });

    return all;
}

但这里存在核心问题:虽然constexpr函数内部可以使用std::string,但由于它依赖堆内存,我们无法直接声明constexpr std::string变量,只能将返回值设为const。原本预期编译器会把constexpr函数计算出的最终字符串缓冲区放入静态存储,但GCC和MSVC都会把整个调用逻辑委托给运行时,生成大量冗余代码。

比如以下代码:

int main()
{
    // 这部分必须在编译期执行,因为static_assert要求编译期常量
    static_assert(GetAllNames<MyEnum>().length() == 17);

    // 但编译器把这里的调用处理成纯运行时操作,甚至不会先把最终字符串放入静态存储再复制到堆
    const std::string names = GetAllNames<MyEnum>();
    printf("%s\n", names.c_str());

    return 0;
}

为了实际利用编译器在编译期计算出的字符串缓冲区,我们可以把constexpr中临时的std::string内容复制到静态存储的容器(比如std::array)里。但因为变量不能作为模板参数,目前的方案需要两次调用函数:

template <size_t Length>
class FakeStringView
{
public:
    constexpr FakeStringView(const std::string_view& s1) : _array{}
    {
        for (auto i = 0; i < s1.length(); ++i)
            _array[i] = s1[i];
    }

    constexpr std::string_view Get() const
    {
        return { _array.data(), _array.size() };
    }

private:
    std::array<char, Length> _array;
};

template <typename E>
constexpr auto GetAllNames()
{
    // 两次调用:一次获取长度作为模板参数,一次获取字符串内容
    return FakeStringView<GetAllNamesImpl<E>().length()>(GetAllNamesImpl<E>());
}

constexpr auto fakestringview = GetAllNames<MyEnum>();
std::cout << fakestringview.Get();

当前的疑问是:是否已有标准方案或更优的实现方式,能避免重复调用constexpr函数、浪费编译期计算成果?

内容的提问来源于stack exchange,提问作者user450775

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:25:15