// Copyright (c) 2016-2021 Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PFR_IO_FIELDS_HPP #define BOOST_PFR_IO_FIELDS_HPP #pragma once #include #include #include #include // metaprogramming stuff #include #include #include #include /// \file boost/pfr/io_fields.hpp /// Contains IO manupulator \forcedlink{io_fields} to read/write \aggregate `value` field-by-field. /// /// \b Example: /// \code /// struct my_struct { /// int i; /// short s; /// }; /// /// std::ostream& operator<<(std::ostream& os, const my_struct& x) { /// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }" /// } /// /// std::istream& operator>>(std::istream& is, my_struct& x) { /// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }" /// } /// \endcode /// /// \podops for other ways to define operators and more details. /// /// \b Synopsis: namespace boost { namespace pfr { namespace detail { template struct io_fields_impl { T value; }; template std::basic_ostream& operator<<(std::basic_ostream& out, io_fields_impl&& x) { const T& value = x.value; constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count(); out << '{'; #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE detail::print_impl<0, fields_count_val>::print(out, detail::tie_as_tuple(value)); #else ::boost::pfr::detail::for_each_field_dispatcher( value, [&out](const auto& val) { // We can not reuse `fields_count_val` in lambda because compilers had issues with // passing constexpr variables into lambdas. Computing is again is the most portable solution. constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count(); detail::print_impl<0, fields_count_val_lambda>::print(out, val); }, detail::make_index_sequence{} ); #endif return out << '}'; } template std::basic_ostream& operator<<(std::basic_ostream& out, io_fields_impl&& x) { return out << io_fields_impl&>{x.value}; } template std::basic_istream& operator>>(std::basic_istream& in, io_fields_impl&& x) { T& value = x.value; constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count(); const auto prev_exceptions = in.exceptions(); in.exceptions( typename std::basic_istream::iostate(0) ); const auto prev_flags = in.flags( typename std::basic_istream::fmtflags(0) ); char parenthis = {}; in >> parenthis; if (parenthis != '{') in.setstate(std::basic_istream::failbit); #if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE detail::read_impl<0, fields_count_val>::read(in, detail::tie_as_tuple(value)); #else ::boost::pfr::detail::for_each_field_dispatcher( value, [&in](const auto& val) { // We can not reuse `fields_count_val` in lambda because compilers had issues with // passing constexpr variables into lambdas. Computing is again is the most portable solution. constexpr std::size_t fields_count_val_lambda = boost::pfr::detail::fields_count(); detail::read_impl<0, fields_count_val_lambda>::read(in, val); }, detail::make_index_sequence{} ); #endif in >> parenthis; if (parenthis != '}') in.setstate(std::basic_istream::failbit); in.flags(prev_flags); in.exceptions(prev_exceptions); return in; } template std::basic_istream& operator>>(std::basic_istream& in, io_fields_impl&& ) { static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier."); return in; } template std::basic_istream& operator>>(std::basic_istream& in, io_fields_impl&& ) { static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped temporary of type T."); return in; } } // namespace detail /// IO manupulator to read/write \aggregate `value` field-by-field. /// /// \b Example: /// \code /// struct my_struct { /// int i; /// short s; /// }; /// /// std::ostream& operator<<(std::ostream& os, const my_struct& x) { /// return os << boost::pfr::io_fields(x); // Equivalent to: os << "{ " << x.i << " ," << x.s << " }" /// } /// /// std::istream& operator>>(std::istream& is, my_struct& x) { /// return is >> boost::pfr::io_fields(x); // Equivalent to: is >> "{ " >> x.i >> " ," >> x.s >> " }" /// } /// \endcode /// /// Input and output streaming operators for `boost::pfr::io_fields` are symmetric, meaning that you get the original value by streaming it and /// reading back if each fields streaming operator is symmetric. /// /// \customio template auto io_fields(T&& value) noexcept { return detail::io_fields_impl{std::forward(value)}; } }} // namespace boost::pfr #endif // BOOST_PFR_IO_FIELDS_HPP