How do I create a template function to print based on container passed to it?

It'd be very useful if I could create a generic print function that takes a STL container object (queue, deque, vector, stack, map, etc...) and prints it a certain way depending on the container.

1. Assume all containers will store ints. Map will store <int,int>.
2. Would it be more difficult to extend it so that it doesn't matter what types the container stores?

template <typename variable_container>
void print(variable_container c)
{
if(c is a queque)
print elements front to back
else if(c is a stack)
print elements top to bottom
....
}
> prints it a certain way depending on the container.
if the function depends on the type of its arguments, then don't do a template, just several overloads.

For containers like array, vector, list, set, map, you may use ranged loops
1
2
for(const auto &x : container)
   out << x << ' '; //you'll need to provide a method to print a pair for map 

However, stack, queue, priority_queue, are not iterable and so you'll need to provide overloads/specializations for them (perhaps there is an easy way to get the underlying container)


About the type of the element, it wouldn't matter as long as it is printable.
If your function needs to create an auxiliar object (for example, to store s.top()), you may get the type with container::value_type (or perhaps just use auto)
Last edited on
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
#include <iostream>

namespace impl
{
    template < typename T > inline void do_print( const T& v, std::ostream& stm ) { stm << v << ' ' ; }

    template < typename F, typename S > // print pair
    inline void do_print( const std::pair<F,S>& p, std::ostream& stm )
    { stm << '{' << p.first << ',' << p.second << "} " ; }
}

template < typename... ARGS, template < typename... > class SEQ  > // print for standard contaners
void print( const SEQ<ARGS...>& seq, std::ostream& stm = std::cout, typename SEQ<ARGS...>::iterator* = 0  )
{ stm << "[ " ; for( const auto& v : seq ) impl::do_print(v,stm) ; stm << "]\n" ; }

// overload for C-style array
template < typename T, std::size_t N > void print( T (&seq)[N], std::ostream& stm = std::cout )
{ stm << "[ " ; for( const auto& v : seq ) impl::do_print(v,stm) ; stm << "]\n" ; }

#include <array> // overload for std::array
template < typename T, std::size_t N > void print( const std::array<T,N>& seq, std::ostream& stm = std::cout )
{ stm << "[ " ; for( const auto& v : seq ) impl::do_print(v,stm) ; stm << "]\n" ; }

#include <vector>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <string>

int main()
{
    { int seq[] { 1, 2, 3, 4 } ; print(seq) ; }
    { std::array<int,4> seq{ { 1, 2, 3, 4 } } ; print(seq) ; }
    
    { std::vector<std::string> seq{ "abc", "efg", "hijkl", "mnopqrs" } ; print(seq) ; }
    { std::deque<int> seq{ 1, 2, 3, 4 } ; print(seq) ; }
    { std::list<int> seq{ 1, 2, 3, 4 } ; print(seq) ; }
    
    { std::set<int> seq{ 1, 2, 3, 4 } ; print(seq) ; }
    { std::multiset<int> seq{ 1, 2, 3, 1, 2, 4 } ; print(seq) ; }
    { std::unordered_set<int> seq{ 1, 2, 3, 4 } ; print(seq) ; }
    { std::unordered_multiset<std::string> seq{ "abc", "defg", "abc", "hij", "defg", "abc" } ; print(seq) ; }
    
    { std::map<int,int> seq{ {1, 0}, {2, 3}, {4, 5} } ; print(seq) ; }
    { std::multimap<int,int> seq{ {1, 0}, {2, 3}, {4, 5}, {2,8} } ; print(seq) ; }
    { std::unordered_map<std::string,int> seq{ {"zero", 0}, {"two", 2}, {"five", 5}, {"twelve", 12} } ; print(seq) ; }
    { std::unordered_multimap<int,int> seq{ {1, 0}, {2, 3}, {4, 5}, {2,8} } ; print(seq) ; }
}

http://coliru.stacked-crooked.com/a/4cfda296668e048b
Improved version: handles nested sequences and ADL-selected overloads for begin/end

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
#include <iostream>
#include <type_traits>
#include <iterator>
#include <utility>
#include <string>

namespace detail
{
    template < typename T > struct has_begin
    {
        template < typename U > static std::true_type test( U&, decltype( begin( std::declval<U&>() ) )* ) ;
        template < typename U > static std::false_type test( U&, ... ) ;

        using type = decltype( test( std::declval<T&>(), nullptr ) ) ;
        static constexpr bool value = type::value ;
    };

    template < typename T > typename std::enable_if< has_begin<T>::value, std::ostream& >::type
    print( std::ostream& stm, const T& seq ) ;
    template < typename T > typename std::enable_if< !has_begin<T>::value, std::ostream& >::type
    print( std::ostream& stm, const T& v ) ;
    std::ostream& print( std::ostream& stm, const std::string& str ) { return stm << '"' << str << '"' ;}

    template < typename F, typename S > std::ostream& print( std::ostream& stm, const std::pair<F,S>& pair )
    { return print( print( stm << "{ ", pair.first ) << ", ", pair.second ) << " }" ; }

    template < typename T > typename std::enable_if< has_begin<T>::value, std::ostream& >::type
    print( std::ostream& stm, const T& seq )
    {
        stm << "[ " ;
        for( const auto& v : seq ) print( stm, v ) << ' ' ;
        return stm << ']' ;
    }

    template < typename T > typename std::enable_if< !has_begin<T>::value, std::ostream& >::type
    print( std::ostream& stm, const T& v ) { return stm << v ; }
}

template < typename T > std::ostream& print( const T& v, std::ostream& stm = std::cout )
{ return detail::print(stm,v) ; }

#include <map>
#include <vector>
#include <unordered_set>

int main()
{
    // array of map of vector of strings to multiset of int
    const std::map< std::vector<std::string>, std::unordered_multiset<int> > seq[2] 
    {
        { { { "abc", "de" }, { 0, 1, 0, 2, 1 } }, { { "def", "ghi" }, { 7, 8, 8, 8, 7, 8, 7 } } },
        { { { "j", "kl", "m" }, { 3, 3, 4 } }, { { "nop", "qrst" }, { 5, 6, 6, 7 } } }
    };

    print(seq) << '\n' ;
}

http://coliru.stacked-crooked.com/a/560b19a2fd047ebb
http://rextester.com/FQGRIV92074
Topic archived. No new replies allowed.