【问题标题】:implement STL pretty printing using Boost HOF使用 Boost HOF 实现 STL 漂亮打印
【发布时间】: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::vector{1234, 23, 2, 3, 3}, "abc",
      std::vector{
          std::vector{11, 12, 13}, std::vector{15, 16, 17}, std::vector{19}});
  print(t3, "xxxx", 55, m, std::vector<std::string>{"x"}, XX{66});
  // (((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)
}

【问题讨论】:

    标签: c++ c++11 boost containers string-formatting


    【解决方案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)...); }
    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多