| 1 | // Copyright 2016-2024 Antony Polukhin |
| 2 | |
| 3 | // Distributed under the Boost Software License, Version 1.0. |
| 4 | // (See the accompanying file LICENSE_1_0.txt |
| 5 | // or a copy at <http://www.boost.org/LICENSE_1_0.txt>.) |
| 6 | |
| 7 | //[pfr_sample_printing |
| 8 | /*` |
| 9 | The following example shows how to write your own io-manipulator for printing: |
| 10 | */ |
| 11 | #include <boost/pfr/ops.hpp> |
| 12 | #include <ostream> |
| 13 | |
| 14 | namespace my_ns { |
| 15 | |
| 16 | /// Usage: |
| 17 | /// struct foo {std::uint8_t a, b;}; |
| 18 | /// ... |
| 19 | /// std::cout << my_ns::my_io(foo{42, 22}); |
| 20 | /// |
| 21 | /// Output: 42, 22 |
| 22 | template <class T> |
| 23 | auto my_io(const T& value); |
| 24 | |
| 25 | namespace detail { |
| 26 | // Helpers to print individual values |
| 27 | template <class T> |
| 28 | void print_each(std::ostream& out, const T& v) { out << v; } |
| 29 | void print_each(std::ostream& out, std::uint8_t v) { out << static_cast<unsigned>(v); } |
| 30 | void print_each(std::ostream& out, std::int8_t v) { out << static_cast<int>(v); } |
| 31 | |
| 32 | // Structure to keep a reference to value, that will be ostreamed lower |
| 33 | template <class T> |
| 34 | struct io_reference { |
| 35 | const T& value; |
| 36 | }; |
| 37 | |
| 38 | // Output each field of io_reference::value |
| 39 | template <class T> |
| 40 | std::ostream& operator<<(std::ostream& out, io_reference<T>&& x) { |
| 41 | const char* sep = "" ; |
| 42 | |
| 43 | boost::pfr::for_each_field(x.value, [&](const auto& v) { |
| 44 | out << std::exchange(obj&: sep, new_val: ", " ); |
| 45 | detail::print_each(out, v); |
| 46 | }); |
| 47 | return out; |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | // Definition: |
| 52 | template <class T> |
| 53 | auto my_io(const T& value) { |
| 54 | return detail::io_reference<T>{value}; |
| 55 | } |
| 56 | |
| 57 | } // namespace my_ns |
| 58 | //] [/pfr_sample_printing] |
| 59 | |
| 60 | |
| 61 | #include <iostream> |
| 62 | #include <sstream> |
| 63 | |
| 64 | int main() { |
| 65 | struct foo {std::uint8_t a, b;}; |
| 66 | |
| 67 | std::ostringstream oss; |
| 68 | oss << my_ns::my_io(value: foo{.a: 42, .b: 22}); |
| 69 | |
| 70 | if (oss.str() != "42, 22" ) { |
| 71 | return 1; |
| 72 | } |
| 73 | |
| 74 | struct two_big_strings { |
| 75 | std::string first; |
| 76 | std::string second; |
| 77 | }; |
| 78 | |
| 79 | #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE |
| 80 | const char* huge_string = "Some huge string that should not fit into std::string SSO." |
| 81 | "And by 'huge' I mean really HUGE string with multiple statements and a lot of periods........." |
| 82 | ; |
| 83 | |
| 84 | oss.str(s: {}); |
| 85 | oss << my_ns::my_io(value: two_big_strings{ |
| 86 | .first: huge_string, .second: huge_string |
| 87 | }); |
| 88 | |
| 89 | if (oss.str() != huge_string + std::string(", " ) + huge_string) { |
| 90 | return 2; |
| 91 | } |
| 92 | #endif |
| 93 | |
| 94 | return 0; |
| 95 | } |
| 96 | |