gpt4 book ai didi

split - 如何使用 C++20 std::views::split 将 std::string_views 拆分为类似元组的对象?

转载 作者:行者123 更新时间:2023-12-04 15:22:16 26 4
gpt4 key购买 nike

根据 this problem ,我们可以使用 C++20 的 std::views::splitstd::string_view 拆分为 std::string_view 的范围:

std::string_view s = "this should be split into string_views";
auto views = s | std::views::split(' ')
| std::views::transform([](auto&& rng) {
return std::string_view(&*rng.begin(), std::ranges::distance(rng));
});

如果我想将那些 std::string_view 存储到一些类似元组的对象中,例如 Boost.Fusion.Sequencestd::tuple,或 std::array:

// magic function
auto tuple_like = to_tuple_like(views);

我该怎么做?有没有不需要创建像 std::vector 这样的中介的解决方案?请注意,原点 s 不是 constexpr

最佳答案

这里是“魔术函数”的示例实现,可将您的 View 转换为字符串 View 的元组

#include <iostream>

#include <algorithm>
#include <array>
#include <ranges>
#include <string_view>
#include <tuple>

template <std::size_t tup_size>
struct TupleType {

};

/*
must be manually defined for each size you want to support
*/
template <>
struct TupleType<6> {
using type = std::tuple<
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view>;
};

template <>
struct TupleType<7> {
using type = std::tuple<
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view>;
};

template <std::size_t idx, class Tup, class It>
constexpr void TupleAssignImpl(Tup& tup, It& it) {
std::get<idx>(tup) = *it;
++it;
}

template <class Tup, class It>
constexpr void AssignEachImpl(Tup& tup, It& it) {
}

template <std::size_t idx, std::size_t ... Is, class Tup, class It>
constexpr void AssignEachImpl(Tup& tup, It& it) {
TupleAssignImpl<idx>(tup, it);
AssignEachImpl<Is...>(tup, it);
}

template <class Tup, class It, std::size_t ... Is>
constexpr void AssignEach(Tup& tup, It& it, std::index_sequence<Is...>) {
AssignEachImpl<Is...>(tup, it);
}

template <std::size_t size, class Range>
constexpr auto ToTuple(Range const& rng) {
auto tup = typename TupleType<size>::type{};
auto it = std::ranges::begin(rng);
AssignEach(tup, it, std::make_index_sequence<size>{});
return tup;
}

int main() {
constexpr std::string_view s = "this should be split into string_views";
constexpr auto views = s | std::views::split(' ')
| std::views::transform([](auto&& rng) {
return std::string_view(&*rng.begin(), std::ranges::distance(rng));
});
constexpr auto sz = std::distance(
std::ranges::begin(views),
std::ranges::end(views));
auto tup = ToTuple<sz>(views);
static_assert(std::is_same_v<decltype(tup), std::tuple<
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view,
std::string_view>>);

std::cout << std::get<0>(tup) << std::endl;
std::cout << std::get<1>(tup) << std::endl;
std::cout << std::get<2>(tup) << std::endl;
std::cout << std::get<3>(tup) << std::endl;
std::cout << std::get<4>(tup) << std::endl;
std::cout << std::get<5>(tup) << std::endl;
}

输出:

this

should

be

split

into

string_views

一些评论:

一般来说,可能有(很可能是)更好的方法来实现这一点。这只是我的方法。

我觉得必须为要支持的每种大小的元组手动定义 TupleType 的特化有点笨拙。尽管由于在编译时必须严格知道元组的类型,所以我不知道另一种方法。

有了 AssignEach,我宁愿写一个简单的 for 循环。例如

for (std::size_t i = 0; i < size; ++i) {
std::get<i>(tup) = *it;
++it;
}

但当然 std::get 的参数必须在编译时严格知道,所以我使用 AssignEach 作为解决方法。

元组的大小必须作为模板参数提供给 ToTuple,因为,为了正常工作,我们必须保证在编译时知道元组的大小。

作为最后的说明:正如其他人所指出的,也许使用 std::tuple 而不是同质范围的调用在这里是有问题的。但是你问如何做到,这是一种方法。

编辑:

如果您可以使用类似元组的 std::array,则该方法会简单得多。不需要 TupleTypeAssignEach 解决方法的专门化。

#include <iostream>

#include <algorithm>
#include <array>
#include <ranges>
#include <string_view>



template <std::size_t size, class Range>
constexpr auto ToTuple(Range const& rng) {
auto array = std::array<std::string_view, size>{};
std::copy(std::ranges::begin(rng), std::ranges::end(rng),
array.begin());
return array;
}


int main() {
constexpr std::string_view s = "this should be split into string_views";
constexpr auto views = s | std::views::split(' ')
| std::views::transform([](auto&& rng) {
return std::string_view(&*rng.begin(), std::ranges::distance(rng));
});
constexpr auto sz = std::distance(
std::ranges::begin(views),
std::ranges::end(views));

auto tup = ToTuple<sz>(views);

for (const auto str : tup) {
std::cout << str << std::endl;
}
}

注意:输出与元组示例相同

关于split - 如何使用 C++20 std::views::split 将 std::string_views 拆分为类似元组的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63045426/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com