这是一个将视图转换为字符串视图元组的“魔法函数”的示例实现。
#include <iostream>
#include <algorithm>
#include <array>
#include <ranges>
#include <string_view>
#include <tuple>
template <std::size_t tup_size>
struct TupleType {
};
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,则方法可以简单得多。不需要特化TupleType和AssignEach的解决方法。
#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;
}
}
注意:输出与元组示例相同。
std::string_view
(例如 "1"、"0.34"、"hello"),并使用boost::fusion
反射技巧(即BOOST_FUSION_ADAPT_STRUCT
)将不同类型的值存储到一些用户定义的struct
中。 - 康桓瑋boost::fusion
可以将std::array
或类似的聚合作为其过程的输入。 - Nicol Bolas