Как написать цикл для последовательности Hana?

У меня есть последовательность Boos.Hana, и я хотел бы распечатать ее на экране, разделенные запятыми. Однако запятые разделяют только элементы, поэтому я должен проверить, нахожусь ли я на последнем элементе.

В настоящее время мой хак довольно плох (смотрит на указатель и приводит к void*,

template<class P, class... Ts>
decltype(auto) operator<<(
std::ostream& os,
boost::hana::tuple<Ts...> const& tpl
){
os << "{";
boost::hana::for_each(
tpl, [&](auto& x){
os << x;
if((void*)&boost::hana::back(tpl) != (void*)&x) os << ", ";
}
);
return os << "}";
}

В случае Boost.Fusion это было сложнее, потому что я использую итераторы fusion (boost::fusion::begin а также boost::fusion::end) но по крайней мере я мог бы сравнить итераторы. (bool last = result_of::equal_to<typename result_of::next<First>::type, Last>::value).

Другой способ задать этот вопрос — есть ли (мета) итераторы в Hana.

1

Решение

Во-первых, чтобы ответить на ваш комментарий, drop_back делает копию. Все алгоритмы в Хане делают копии и готовы, как задокументировано Вот.

Во-вторых, вы могли бы использовать hana::intersperse добавить запятую между каждым элементом, в результате чего-то вроде

template<class P, class... Ts>
decltype(auto) operator<<(
std::ostream& os,
boost::hana::tuple<Ts...> const& tpl
){
os << "{";
boost::hana::for_each(boost::hana::intersperse(tpl, ", "),
[&](auto const& x){
os << x;
});
return os << "}";
}

Тем не менее, лучшее решение, вероятно, будет использовать experimental::print, который делает именно то, что вы хотите:

#include <boost/hana/experimental/printable.hpp>
#include <boost/hana/tuple.hpp>
#include <iostream>

int main() {
auto ts = hana::make_tuple(1, 2, 3);
std::cout << hana::experimental::print(ts);
}

редактировать

Если вы хотите использовать intersperse Решение, но не хотите делать копию последовательности, вы можете сделать следующее:

#include <boost/hana.hpp>
#include <functional>
#include <iostream>
namespace hana = boost::hana;

template <class... Ts>
decltype(auto) operator<<(std::ostream& os, hana::tuple<Ts...> const& tpl) {
os << "{";
char const* sep = ", ";
auto refs = hana::transform(tpl, [](auto const& t) { return std::ref(t); });
hana::for_each(hana::intersperse(refs, std::ref(sep)),
[&](auto const& x){
os << x.get();
});
return os << "}";
}

Но на самом деле, вы, вероятно, должны использовать hana::experimental::print, И если ваш вариант использования критичен к производительности, и вы хотите избежать создания std::stringЯ бы усомнился в использовании std::ostream на первом месте.

Конец редактирования

4

Другие решения

Благодаря @cv_and_he я смог найти решение. Хотя это не выглядит самым элегантным, потому что это приведет к дублированию кода (а также к копированию).

template<class P, class... Ts>
decltype(auto) operator<<(
std::ostream& os,
boost::hana::tuple<Ts...> const& tpl
){
os << "{";
boost::hana::for_each(
boost::hana::drop_back(tpl), [&](auto const& x){
os << x << ", ";
}
);
os << boost::hana::back(x);
return os << "}";
}
0

То же, что и оригинал, но меньше взлома, так как он использует boost::hana::equal сравнить тождества.

template<class P, class... Ts>
decltype(auto) operator<<(
std::ostream& os,
boost::hana::tuple<Ts...> const& tpl
){
os << "{";
boost::hana::for_each(
tpl, [&](auto& x){
os << x;
if(not boost::hana::equal(&x, &boost::hana::back(tpl))){p << ", ";}
}
);
return os << "}";
}
0

Это решение, основанное на указателях, чтобы избежать как копий, так и std::cref,

template<class P, class... Ts>
decltype(auto) operator<<(
std::ostream& os,
boost::hana::tuple<Ts...> const& tpl
){
os << "{";
std::string sep = ", ";
hana::for_each(
hana::intersperse(
hana::transform(tpl, [](auto& t){return &t;}),
&sep
), [&](auto x){os << *x;}
);
return os << "}";
}
0
По вопросам рекламы [email protected]