1

我有一个 Boos.Hana 序列,我想将它打印到屏幕上,用逗号分隔。但是逗号仅分隔元素,所以我必须检查我是否在最后一个元素。

目前我的 hack 非常糟糕(查看指针并转换为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 中是否有(元)迭代器。

4

4 回答 4

4

首先,要回答您的评论,请drop_back复制一份。Hana 中的所有算法都会复制并渴望,如此处所述

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

编辑结束

于 2016-01-10T23:11:27.960 回答
0

感谢@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 << "}";
}
于 2016-01-10T08:21:53.510 回答
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 << "}";
}
于 2016-01-11T16:11:06.983 回答
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 << "}";
}
于 2016-01-12T03:48:59.117 回答