如何使用 >= C++23 从 std::ranges::lazy_split_view 提取 std::string_view 标记?

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

在编译时解析器中,我需要提取

std::string_value
文字的一部分并对其进行解码。

不幸的是没有编译,我所做的一个最小的例子是:

#include <charconv>
#include <iostream>
#include <optional>
#include <ranges>
#include <string_view>

template <typename X>
static constexpr X svtox(const std::string_view &sv)
{
    X value;
    auto result = std::from_chars(sv.data(), sv.data() + sv.size(), value);
    return value;
}

static constexpr float parse(const std::string_view &sv)
{
    const std::ranges::lazy_split_view tokens(sv, " ");
    auto token_iterator = tokens.cbegin();
    const auto keyword = *token_iterator++;
    return svtox<float>(*token_iterator++);
}

int main()
{
    const auto sv = std::string_view{"Whatever 1.0"};
    float f = parse(sv);
    std::cout << f;
}

可以肯定的是,真实的图案更复杂,提取的图案也更多,其中包含错误处理并进一步处理,而不仅仅是打印。

当我使用

c++ -std=gnu++2b -Wall -o test test.cpp
调用 GCC 13.2 时,出现以下错误:

test.cpp: In function ‘constexpr float parse(const std::string_view&)’:
test.cpp:20:25: error: invalid initialization of reference of type ‘const std::string_view&’ {aka ‘const std::basic_string_view<char>&’} from expression of type ‘std::basic_const_iterator<std::ranges::lazy_split_view<std::basic_string_view<char>, std::ranges::ref_view<const char [2]> >::_OuterIter<true> >::__reference’ {aka ‘std::__common_reference_impl<const std::ranges::lazy_split_view<std::basic_string_view<char>, std::ranges::ref_view<const char [2]> >::_OuterIter<true>::value_type&&, std::ranges::lazy_split_view<std::basic_string_view<char>, std::ranges::ref_view<const char [2]> >::_OuterIter<true>::value_type, 3, void>::type’}
   20 |     return svtox<float>(*token_iterator++);
      |                         ^~~~~~~~~~~~~~~~~
test.cpp:8:50: note: in passing argument 1 of ‘constexpr X svtox(const std::string_view&) [with X = float; std::string_view = std::basic_string_view<char>]’
    8 | static constexpr X svtox(const std::string_view &sv)
      |                          ~~~~~~~~~~~~~~~~~~~~~~~~^~

我所处的环境可以使用以下

Dockerfile
(简化示例)重新创建:

FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu

RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && apt-get -y dist-upgrade && apt-get install -y ubuntu-release-upgrader-core && do-release-upgrade -p -f DistUpgradeViewNonInteractive -m server --allow-third-party && apt-get -y dist-upgrade && do-release-upgrade -d -f DistUpgradeViewNonInteractive -m server --allow-third-party && apt-get -y dist-upgrade

我对现代(对我来说是 C++98 之后的)C++ 相当陌生,所以我想我错过了一些简单的东西。

c++ split std c++23 string-view
2个回答
0
投票

您遇到的问题是由于

std::degrees::lazy_split_view
返回的范围为
std::degrees::subrange items
,而不是
std::string_view
。 您可以通过使用
std::degrees::subrange
std::string_view
成员函数将
bottom()
转换为
std::degrees::subrange
来获取基础范围,然后从中构建
std::string_view
。 您可以修改您的
parse
函数来执行此操作:

static constexpr float parse(const std::string_view &sv)
{
    const std::ranges::lazy_split_view tokens(sv, " ");
    auto token_iterator = tokens.cbegin();
    const auto keyword = *token_iterator++;
    return svtox<float>(std::string_view{token_iterator->base().begin(), token_iterator->size()});
}

这将从

std::string_view
返回的
std::ranges::subrange
构造一个
lazy_split_view
,然后可以将其传递给
svtox
函数。请注意,这假设
subrange
的基础范围是连续的,
std::string_view
就是这种情况。如果您要分割不同类型的范围,则需要确保它也是连续的。


0
投票

lazy_split_view
分割的子范围最多仅模型
forward_range
,这就是为什么它被称为“惰性”。构造
string_view
需要
contiguous_range

相反,您可以使用

split_view
并将分割子范围显式转换为
string_view
:

auto tokens = sv | std::views::split(' ')
                 | std::views::transform([](auto r) { return std::string_view(r); });
auto token_iterator = tokens.cbegin();

请注意,与

lazy_split_view
相比,
split_view
不是 const-iterable,因此您不能将其声明为 const 对象。

演示

© www.soinside.com 2019 - 2024. All rights reserved.