使用 Boost HOF 实现 STL 漂亮打印

Posted

技术标签:

【中文标题】使用 Boost HOF 实现 STL 漂亮打印【英文标题】:implement STL pretty printing using Boost HOF 【发布时间】:2018-08-30 02:26:09 【问题描述】:

任意类型的漂亮打印容器

以下几行代码提供与question 中的prettyprint.hpp 相同的输出, 但输出流仅限于std::cout

如何使用boost::hof重写这些代码以提供类似print(std::ostream&, ...)的接口?

#include <iostream>
#include <boost/hof.hpp>

BOOST_HOF_STATIC_LAMBDA_FUNCTION(simple_print) = //boost::hof::proj(
    boost::hof::fix(boost::hof::first_of(
        [](auto, const auto& x) -> decltype(std::cout << x, void()) 
          std::cout << x;
        ,
        [](auto self, const auto& range)
         -> decltype(self(*std::begin(range)), void()) 
          bool sep = false;
          std::cout << '';
          for (const auto& x : range) 
            if (sep)
              std::cout << ',';
            else
              sep = true;
            self(x);
          
          std::cout << '';
        ,
        [](auto self, const auto& tuple) 
          using namespace boost::hof;
          std::cout << '(';
          bool sep = false;
          unpack(proj([&](const auto& i) 
            if (sep)
              std::cout << ',';
            else
              sep = true;
            self(i);
          ))(tuple);
          std::cout << ')';
        ));//)));

template <typename... Args>
void print(Args&&... args) 
  simple_print(std::make_tuple(std::forward<Args>(args)...));



//---- user code ---
struct XX 
  int n = 0;

  friend std::ostream& operator<<(std::ostream& os, const XX& o) 
    return os << o.n << "XX";
  
;

int main() 

  std::vector v                = 1, 2, 3, 4;
  std::map<std::string, int> m = "a", 30, "bb", 31, "ccc", 32;

  auto t  = std::make_tuple(6, 7, 8, 9);
  auto t2 = std::make_tuple(11, std::ref(v), t);
  auto t3 = std::make_tuple(t2, std::vector1234, 23, 2, 3, 3, "abc",
      std::vector
          std::vector11, 12, 13, std::vector15, 16, 17, std::vector19);
  print(t3, "xxxx", 55, m, std::vector<std::string>"x", XX66);
  // (((11, [1, 2, 3, 4], (6, 7, 8, 9)), [1234, 23, 2, 3, 3], abc, [[11, 12,
  // 13], [15, 16, 17], [19]]), xxxx, 55, [(a, 30), (bb, 31), (ccc, 32)], [x],
  // 66XX)

【问题讨论】:

【参考方案1】:

只需添加一个参数来传递 ostream 就足够了:

BOOST_HOF_STATIC_LAMBDA_FUNCTION(simple_print_ex) = boost::hof::fix(
    boost::hof::first_of(
        [](auto, auto& os, const auto &x) -> decltype(os << x, void())  os << x; ,
        [](auto self, auto& os, const auto &range) -> decltype(self(os, *std::begin(range)), void()) 
            bool sep = false;
            os << '';
            for (const auto &x : range) 
                sep = !sep || os << ',';
                self(os, x);
            
            os << '';
        ,
        [](auto self, auto& os, const auto &tuple) 
            using namespace boost::hof;
            os << '(';
            bool sep = false;
            unpack(proj([&](const auto &i) 
                sep = !sep || os << ',';
                self(os, i);
            ))(tuple);
            os << ')';
        ));

template <typename Ostream, typename... Args> void print_ex(Ostream& os, Args &&... args)  simple_print_ex(os, std::make_tuple(std::forward<Args>(args)...)); 

现在你可以像这样使用它了:

Live On Wandbox

std::ofstream ofs("test.txt");
print_ex(ofs, t3, "xxxx", 55, m, std::vector<std::string> "x" , XX 66 );
ofs << "\n";

当然,旧的print 现在可以成为微不足道的转发包装器了:

template <typename... Args> void print(Args &&... args) 
    print_ex(std::cout, std::forward<Args>(args)...);

上市

Live On Wandbox

#include <boost/hof.hpp>
#include <iostream>

BOOST_HOF_STATIC_LAMBDA_FUNCTION(simple_print_ex) = boost::hof::fix(
    boost::hof::first_of(
        [](auto, auto& os, const auto &x) -> decltype(os << x, void())  os << x; ,
        [](auto self, auto& os, const auto &range) -> decltype(self(os, *std::begin(range)), void()) 
            bool sep = false;
            os << '';
            for (const auto &x : range) 
                sep = !sep || os << ',';
                self(os, x);
            
            os << '';
        ,
        [](auto self, auto& os, const auto &tuple) 
            using namespace boost::hof;
            os << '(';
            bool sep = false;
            unpack(proj([&](const auto &i) 
                sep = !sep || os << ',';
                self(os, i);
            ))(tuple);
            os << ')';
        ));

template <typename Ostream, typename... Args> void print_ex(Ostream& os, Args &&... args)  simple_print_ex(os, std::make_tuple(std::forward<Args>(args)...)); 
template <typename... Args> void print(Args &&... args)  print_ex(std::cout, std::forward<Args>(args)...); 

//---- user code ---
struct XX 
    int n = 0;

    friend std::ostream &operator<<(std::ostream &os, const XX &o)  return os << o.n << "XX"; 
;

#include <map>
#include <vector>
#include <fstream>
int main() 
    using namespace std::string_literals;

    std::vector v =  1, 2, 3, 4 ;
    std::map m  std::pair  "a"s, 30 ,  "bb", 31 ,  "ccc", 32  ;

    auto t = std::make_tuple(6, 7, 8, 9);
    auto t2 = std::make_tuple(11, std::ref(v), t);
    auto t3 = std::make_tuple(t2, std::vector 1234, 23, 2, 3, 3 , "abc",
                              std::vector std::vector 11, 12, 13 , std::vector 15, 16, 17 , std::vector 19  );
    std::ofstream ofs("test.txt");
    print_ex(ofs, t3, "xxxx", 55, m, std::vector<std::string> "x" , XX 66 );
    ofs << "\n";

    print(t3, "xxxx", 55, m, std::vector<std::string> "x" , XX 66 );

【讨论】:

感谢您的回答。通过您的代码,我发现阻止我添加 Ostream 参数的是第一个 boost::hof::proj 旨在实现 template &lt;typename... Args&gt; void print(Args&amp;&amp;... args) simple_print(std::forward&lt;Args&gt;(args)...);

以上是关于使用 Boost HOF 实现 STL 漂亮打印的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Eclipse CDT 中为 C++ STL 对象启用 gdb 漂亮打印?

有没有实现条件累加的boost或stl函数?

如何在编译时漂亮地打印模板参数的名称

使用 C++ Boost 或 STL 和 Mysql 存储和检索图像

C++ 中的 boost::scoped_ptr 和 STL

大家怎么处理QT库和stl,boost等的关系