在 constexpr 中连接 string_views

问题描述 投票:0回答:3

我正在尝试将

string_views
连接到
constexpr
中。 以下是我的代码的简化版本:

#include <iostream>
#include <string_view>

using namespace std::string_view_literals;

// concatenate two string_views by copying their bytes
// into a newly created buffer
constexpr const std::string_view operator+
    (const std::string_view& sv1, const std::string_view& sv2)
{
    char buffer[sv1.size()+sv2.size()] = {0};
    for(size_t i = 0; i < sv1.size(); i++)
        buffer[i] = sv1[i];
    for(size_t i = sv1.size(); i < sv1.size()+sv2.size(); i++)
        buffer[i] = sv2[i-sv1.size()];
    return std::string_view(buffer, sv1.size()+sv2.size());
}

int main()
{
    const std::string_view sv1("test1;");
    const std::string_view sv2("test2;");
    std::cout << sv1 << "|" << sv2 << ": " << (sv1+sv2+sv1) << std::endl;
    std::cout << "test1;"sv << "|" << "test2;"sv << ": " <<
        ("test1;"sv+"test2;"sv) << std::endl;
    return 0;
}

但是这段代码没有产生我期望的结果。它不是打印

test1;test2;test1
test1;test2;
,而是打印出与随机字符混合的正确字符,就好像我正在访问未初始化的内存一样。

test1;|test2;: F��<��itest;
test1;|test2;: est1;te`�i

但是,如果我删除

constexpr
说明符并将
string_views
替换为
strings
,上面的代码将打印预期的输出。

test1;|test2;: test1;test2;test1;
test1;|test2;: test1;test2;

要么我在代码中遗漏了一些明显的错误,要么有一些关于

constexpr
的内容我还不明白。这是我为新的
string_view
创建缓冲区的方式吗?我还能做什么?或者我想做的事情是不可能的?也许有人可以为我阐明这一点。

c++ c++17 constexpr string-view
3个回答
2
投票

你的任务基本上是不可能的,因为根据定义,

string_view
需要从开始到结束都有连续的非拥有存储。因此无法管理数据的生命周期。

如果您想做这样的事情,您需要创建某种

concatenated_string<>
自定义范围作为返回类型。

至于您的代码产生奇怪结果的具体原因,这只是因为函数退出时

buffer
不再存在。


2
投票

return std::string_view(buffer, sv1.size()+sv2.size());
中,返回的
string_view
视图超出范围的
buffer
,因此您本质上有一个悬空引用。


0
投票

要连接 string_view,请为新 string_view 创建存储。

要将 string_view 和结果连接到 constexpr,请为新 string_view 创建 static 存储。

在C++20中,可以轻松创建constexpr staitc存储。

在C++20之前,你必须使用模板特化和参数包来分配每个元素,这是可能的,但非常复杂。

C++20中有一个例子:

template<const std::string_view &sv1, const std::string_view &sv2>
struct StringViewCat{
    static constexpr auto get_arr()
    {
        std::array<char, sv1.size() + sv2.size()> arr;
        for(auto i = 0; i < sv1.size(); ++i)
            arr[i] = sv1[i];
        for(auto i = 0; i < sv2.size(); ++i)
            arr[i+sv1.size()] = sv2[i];
        
        return arr;
    }
    constexpr static std::array<char, sv1.size() + sv2.size()> arr = get_arr();
    constexpr static std::string_view data{arr.data(), arr.size()};
};

用途:

    static constexpr auto a = "a"sv;
    static constexpr auto b = "b"sv;
    constexpr auto c = StringViewCat<a, b>::data;
© www.soinside.com 2019 - 2024. All rights reserved.