我有一个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的情况下,它更加复杂,因为我使用了融合迭代器(boost::fusion::beginboost::fusion::end),但至少我可以比较这些迭代器。 (bool last = result_of::equal_to<typename result_of::next<First>::type, Last>::value)。

提出此问题的另一种方法是,在Hana中是否有(元)个迭代器。

最佳答案

首先,为了回答您的评论,drop_back会进行复制。 Hana中的所有算法都会复制并渴望,如here所述。

其次,您可以使用 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的用法。

编辑结束

关于c++ - 如何为Hana序列编写for循环?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34702694/

10-11 19:02