
output.hpp#ifndef OUTPUT_RANGE_H #define OUTPUT_RANGE_H #include cstddef // std::byte #include iterator // std::begin/end #include ostream // std::ostream #include tuple // std::tuple/tuple_size #include type_traits// std::false_type/true_type/decay_t/is_same_v/remove_... #include utility // std::declval/pair #ifndef OUTPUT_RANGE_NO_STRING_QUOTE #include string // std::string #include string_view// std::string_view #endif namespace output_range { using std::begin; using std::end; templateclass Rng auto adl_begin(Rng rng) - decltype(begin(rng)) { // Intentionally not using std::forward, as std::begin does not // accept an rvalue reference. return begin(rng); } templateclass Rng auto adl_end(Rng rng) - decltype(end(rng)) { // Intentionally not using std::forward, as std::end does not // accept an rvalue reference. return end(rng); } // Type trait to detect std::pair templatetypename T struct is_pair : std::false_type {}; templatetypename T, typename U struct is_pairstd::pairT, U : std::true_type {}; templatetypename T inline constexpr bool is_pair_v is_pairT::value; // Type trait for tuple-like objects templatetypename T, typename void struct is_tuple_like : std::false_type {}; templatetypename T struct is_tuple_likeT, std::void_tdecltype(std::tuple_sizeT::value) : std::true_type {}; templatetypename T inline constexpr bool is_tuple_like_v is_tuple_likeT::value; // Type traits for ranges templatetypename T, typename void struct is_range : std::false_type {}; templatetypename T struct is_rangeT, std::void_tdecltype(adl_begin(std::declvalT()), adl_end(std::declvalT())) : std::true_type {}; templatetypename T inline constexpr bool is_range_v is_rangeT::value; // Type trait to detect whether an output function already exists templatetypename T struct has_output_function { templateclass U static auto output(U* ptr) - decltype(std::declvalstd::ostream() *ptr, std::true_type{}); templateclass U static std::false_type output(...); static constexpr bool value decltype(outputT(nullptr))::value; }; #ifndef OUTPUT_RANGE_NO_ARRAY_OUTPUT templatetypename T, std::size_t N struct has_output_functionT[N] : std::false_type {}; templatestd::size_t N struct has_output_functionchar[N] : std::true_type {}; templatestd::size_t N struct has_output_functionsigned char[N] : std::true_type {}; templatestd::size_t N struct has_output_functionunsigned char[N] : std::true_type {}; templatestd::size_t N struct has_output_functionconst char[N] : std::true_type {}; templatestd::size_t N struct has_output_functionconst signed char[N] : std::true_type {}; templatestd::size_t N struct has_output_functionconst unsigned char[N] : std::true_type {}; #endif templatetypename T inline constexpr bool has_output_function_v has_output_functionT::value; // Element output function for containers that define a key_type and // have its value type as std::pair templatetypename T, typename Rng auto output_element(std::ostream os, const T element, const Rng, std::true_type) - decltype(std::declvaltypename Rng::key_type(), os); // Element output function for other containers templatetypename T, typename Rng auto output_element(std::ostream os, const T element, const Rng, ...) - decltype(os); // Member output function for tuple-like objects templatetypename Tup, std::size_t... Is void output_tuple_members(std::ostream os, const Tup tup, std::index_sequenceIs...); }// namespace output_range // Output function for tuple-like objects templatetypename T, std::enable_if_t(output_range::is_tuple_like_vT !output_range::is_range_vT), bool true std::ostream operator(std::ostream os, const T tup); // Main output function, enabled only if no output function already exists templatetypename Rng, std::enable_if_t(output_range::is_range_vRng !output_range::has_output_function_vstd::remove_cv_tstd::remove_reference_tRng), bool true std::ostream operator(std::ostream os, Rng rng) { using std::decay_t; using std::is_same_v; using element_type decay_tdecltype(*output_range::adl_begin(rng)); os {; auto end output_range::adl_end(rng); bool on_first_element true; for (auto it output_range::adl_begin(rng); it ! end; it) { if (!on_first_element) { os , ; } else { os ; on_first_element false; } output_range::output_element(os, *it, rng, output_range::is_pairelement_type{}); } if (!on_first_element) {// Not empty os ; } os }; return os; } templatetypename T, std::enable_if_t(output_range::is_tuple_like_vT !output_range::is_range_vT), bool std::ostream operator(std::ostream os, const T tup) { os (; output_range::output_tuple_members(os, tup, std::make_index_sequencestd::tuple_size_vT{}); os ); return os; } namespace output_range { templatetypename T, typename Rng auto output_element(std::ostream os, const T element, const Rng, std::true_type) - decltype(std::declvaltypename Rng::key_type(), os) { output_element(os, element.first, element); os ; output_element(os, element.second, element); return os; } templatetypename T, typename Rng auto output_element(std::ostream os, const T element, const Rng, ...) - decltype(os) { if constexpr (std::is_same_vT, char || std::is_same_vT, signed char) { os \ element \; } else if constexpr (std::is_same_vT, unsigned char || std::is_same_vT, std::byte) { os static_castunsigned(element); } else #ifndef OUTPUT_RANGE_NO_STRING_QUOTE { using DT std::decay_tT; using PT std::remove_cv_tstd::remove_pointer_tDT; if constexpr (std::is_same_vT, std::string || std::is_same_vT, std::string_view || (std::is_pointer_vDT (std::is_same_vPT, char || std::is_same_vPT, signed char || std::is_same_vPT, unsigned char))) { os element ; } else { os element; } } #else { os element; } #endif return os; } templatetypename Tup, std::size_t... Is void output_tuple_members(std::ostream os, const Tup tup, std::index_sequenceIs...) { using std::get; ((os (Is ! 0 ? , : ), output_element(os, getIs(tup), tup)), ...); } }// namespace output_range #endif// OUTPUT_RANGE_H测试#include output.hpp #include iostream #include map int main(int argc, char* argv[]) { std::vectorint v{ 1,2,3,4 }; std::tuplechar, int, float t{ a, 1, 2.0f }; std::mapint, std::string m{ {1,one},{2,two} }; std::cout v std::endl; std::cout m std::endl; std::cout t std::endl; return 0; }输出{ 1, 2, 3, 4 }{ 1 one, 2 two }(a, 1, 2)参考https://github.com/adah1972/output_range创作不易小小的支持一下吧