1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
#include <iostream>
#include <iterator>
#include <ranges> // C++20
#include <map>
#include <tuple>
#include <string>
#include <vector>
#include <tuple>
#include <list>
#include <variant>
static_assert( __cplusplus >= 202002L, "C++20 or later is required" ) ;
namespace print_utils
{
// print generic range (declaration: members of pair/tuple/variant may be ranges)
template < typename OSTREAM, std::ranges::range RANGE >
OSTREAM& operator<<( OSTREAM& stm, const RANGE& seq ) ;
// print std::pair (first:second)
template < typename OSTREAM, typename FIRST, typename SECOND >
OSTREAM& operator<<( OSTREAM& stm, const std::pair<FIRST,SECOND>& pair )
{ return stm << '(' << pair.first << ':' << pair.second << ')' ; }
namespace detail
{
// std::tuple print helper (e1,e2,e3...)
template < typename OSTREAM, typename TUPLE, std::size_t... INDEX >
OSTREAM& print( OSTREAM& stm, const TUPLE& tuple, std::index_sequence<INDEX...> )
{
stm << '(' ;
( ... , ( stm << ( INDEX == 0 ? "" : "," ) << std::get<INDEX>(tuple) ) ) ;
return stm << ')' ;
}
}
// print std::tuple
template < typename OSTREAM, typename... T >
OSTREAM& operator<<( OSTREAM& stm, const std::tuple<T...>& tuple )
{ return detail::print( stm, tuple, std::make_index_sequence< sizeof...(T) >() ) ; }
// print std::variant
template < typename OSTREAM, typename... T >
OSTREAM& operator<<( OSTREAM& stm, const std::variant<T...>& variant )
{ return std::visit( [&] ( auto&& v ) -> OSTREAM& { return stm << v ; }, variant ) ; }
// print generic range
template < typename OSTREAM, std::ranges::range RANGE >
OSTREAM& operator<<( OSTREAM& stm, const RANGE& seq )
{
stm << '[' << ' ' ;
for( const auto& elt : seq ) stm << elt << ' ' ;
return stm << ']' ;
}
}
int main()
{
using namespace print_utils ; // required
int arr[][5] { { 1, 2 }, { 3, 4, 5 }, { 6, 7, 8, 9 } };
std::cout << "2d array: " << arr << '\n' ;
std::wcout << L"2d array: " << arr << L'\n' ;
const std::map< int, std::string > map { { 0, "zero" }, { 1, "one" }, { 2, "two" } } ;
std::cout << "map: " << map << '\n' ;
std::vector vec { map, map } ;
vec.back().emplace( 3, "three" ) ;
std::cout << "vector of maps: " << vec << '\n' ;
struct abc
{
auto begin() const noexcept { return "abcdefghijklmnpqrstuvwxyz" ; }
auto end() const noexcept { return begin() + std::clamp( width, 0, 26 ) ; }
int width = 6 ;
};
const abc chars{6} ;
std::cout << "a custom range: " << chars << '\n' ;
std::tuple< int, const char*, double, abc > tup { 12, "four", 4.5, {4} } ;
std::cout << "tuple: " << tup << '\n' ;
std::list< decltype(tup) > lst { tup, tup, tup } ;
std::wcout << L"list of tuples: " << lst << L'\n' ;
using var_t = std::variant< int, const char*, double, abc, decltype(map) > ;
std::vector<var_t> vecv { var_t(12), var_t("five"), var_t(4.5), var_t( abc{5} ), var_t(map), var_t("six") } ;
std::cout << "vector of variants: " << vecv << '\n' ;
}
| |