template operator<<

i am playing with timers,
I wrote an operator to put a timespec (from time.h)

std::ostream& operator<< ( std::ostream & out, const timespec &ts)

which works dandy.
then I thought, template!
I tried this:

1
2
template<typename T>
std::ostream& operator<<( std::ostream & out, const T  &ts)


ambiguous, maybe it clashes with other standard templates?
so I thought maybe I need a partial specialization:

1
2
template<>
std::ostream& operator<< <timespec>( std::ostream & out, const timespec  &ts)


nope. maybe:

1
2
template<>
std::ostream& operator<< <std::ostream, timespec>( std::ostream & out, const timespec  &ts)


curious as to why it doesn't work.


I'm not sure I follow your intent, but I cut out the following snippets from std_ostream.h:
1
2
3
  template<typename _CharT, typename _Traits>
    basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c);

Here is a the specialization for char:
1
2
3
4
5
6
7
8
9
  template<typename _CharT, typename _Traits>
    basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
    { return (__out << __out.widen(__c)); }

  // Specialization
  template <class _Traits> 
    basic_ostream<char, _Traits>&
    operator<<(basic_ostream<char, _Traits>& __out, char __c);


So, maybe try something like this for the specialization:
1
2
3
4
5
template <class Traits> 
std::basic_ostream<timespec, Traits>&
operator<<(std::basic_ostream<timespec, Traits>& out, const timespec & t) {
    //...
}

Last edited on
It all seems to work for me (although I have don't have the timespec struct by default in windows - I just copied from the internet and pasted it and it all worked). What can I say.

BTW this specialisation:
template<>
std::ostream& operator<< <timespec>( std::ostream & out, const timespec &ts)


should be:
1
2
template <>
std::ostream& operator<< <const timespec>( std::ostream & out, const timespec  &ts)
Last edited on
thank you sir.
no luck.
I was just experimenting.

well it's not important at the moment.
I have a better silly question coming up.

@guestgulkan
yes I tried the const.
still does not work
Last edited on
more interesting, similar concept.
a conceptual template for dumping containers.
(like scripting languages where you can print a list)
But you will need to disambiguate somehow. It will
match any cout << thingy
I suppose some things cannot be done with function templates.



1
2
3
4
5
6
7
8
9
10
11
12
13
template<class T>
std::ostream& operator<<( std::ostream& out, const T & v)
{

    typename T::iterator p = v.begin();
    typename T::iterator end = v.end();
    while( p!= end ) {
        out << *p << '  ';
        ++p;
    }
    return out;

}
Last edited on
a template function to print out a container, works.
if I make it operator<< it is ambiguous.
same signature?? my brain hurts.


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
#include <iostream>
#include <vector>
#include <list>

using namespace std;

typedef vector<string> vec;
typedef list<string> lis;

#define DUMP
template<class T>
#ifdef DUMP
std::ostream& dump ( std::ostream& out, T & v)
#else
std::ostream& operator<< ( std::ostream& out, T & v)
#endif
{
        typename T::iterator p   = v.begin();
        typename T::iterator end = v.end();
        while ( p!= end ) {
            out << *p;  //****  AMBIGUITY IS HERE
            ++p;
        }
        return out;

}


int main(int argc, char ** argv) {

    vec v;
    lis L;
    v.push_back("motherf@");
    L.push_back("twit ");

#ifdef DUMP
    dump(cout, v);
    dump(cout, L);
#else
    cout << v ;
    cout << L << endl;
#endif

    return 0;
}
Last edited on
in case anyone is interested, a template container dumper.
like: cout << my_vector;

still confused over the ambiguity though. but it is late.
any non gcc people can test? curious if it's the same.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<class T>
std::ostream& operator<< ( std::ostream& out, T & v)
{        

       typedef typename T::value_type thingy;

        typename T::iterator p   = v.begin();
        typename T::iterator end = v.end();
        std::ostream_iterator<thingy> oi(out, " ");

        while ( p!= end ) {
            // out << *p; // this causes ambiguity!
            *oi = *p;        // this works.
            ++p;
        }
        return out;

}
Last edited on
i had come up with something (similar?)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::ostream& operator<<( std::ostream& out,  T & v)
{

    typename T::iterator p = v.begin();
    typename T::iterator end = v.end();
    while( p!= end ) {
        out << *p;      
        std::operator << (out, "    ");

        ++p;
    }
    return out;

}


It was really the global overloads for char string " " that was the issue i think.
Last edited on
yes, now you see, that doesn't compile for me.
it's the
 
     out << *p;      

anything, even out << "crapola" blows up.
remove it and it compiles!

my gcc is quite up to date
1
2
3
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070719  [FreeBSD]



my main... (defined in useful/dump.hpp)
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
#include <iostream>
#include <vector>
#include <iterator>
#include <list>
#include <useful/dump.hpp>

using namespace std;

typedef vector<string> vec;
typedef list<string> lis;


int main(int argc, char ** argv) {

    vec v;
    lis L;
    v.push_back("dave");
    v.push_back("dee");
    v.push_back("dozy");
    v.push_back("beaky");
    v.push_back("mick");
    v.push_back("and");
    v.push_back("tich");
    L.push_back("twit ");

    cout << v << endl;
    cout << L << endl;

    return 0;
}
Last edited on
I was using a vector<int> to test with.
If I had taken my own advice about the global overloads for char strings being problematic I would have tested it with vector<string>.

So after amendment my function looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<class T>
std::ostream& operator<<( std::ostream& out,  T & v)
{

    typename T::iterator p = v.begin();
    typename T::iterator end = v.end();
    while( p!= end ) {
        //Avoiding the Global Namespace << overloads - using std:: instead
        std::operator << (out,*p);      
        std::operator << (out, "    ");

        ++p;
    }
    return out;

}


Does that run for you??
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
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
using namespace std;

template <class T>
class STLContainer
{
private:
    const T * pc;

public:
    STLContainer(const T & c):pc(&c){}

    friend ostream & operator<<(ostream & os,STLContainer<T> c)
    {
        typename T::const_iterator it;

        for (it=c.pc->begin(); it!=c.pc->end(); it++)
            os << *it << ' ';

        return os;
    }
};

template <class T>
ostream & operator<<(ostream & os, const vector<T> & c)
{return os << STLContainer<vector<T> >(c);}

template <class T>
ostream & operator<<(ostream & os, const deque<T> & c)
{return os << STLContainer<deque<T> >(c);}

template <class T>
ostream & operator<<(ostream & os, const list<T> & c)
{return os << STLContainer<list<T> >(c);}

template <class T>
ostream & operator<<(ostream & os, const set<T> & c)
{return os << STLContainer<set<T> >(c);}

int main()
{
    vector<string> sv;
    deque<string> sd;
    list<string> sl;
    set<string> ss;

    vector<deque<list<set<string> > > > lol;

    cout << sv;
    cout << sd;
    cout << sl;
    cout << ss;

    cout << lol;

    cout << "OMG it works!..." << endl;
    cout << "hit enter to quit..." << endl;
    cin.get();
};
Last edited on
thank you very much people.

yes guestgulkan that works.

master roshi, very good!
All though you seem to have missed out std::map
;-)

i think i need a rest.
Last edited on
aah strange m4ster roshi I've already done something similar myself.
with vt100 escape sequences, a work-in-progres, only 2 days ago.
brain must be full up.

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
92
93
94
95
96
97
98
99
100
101
102
103
namespace vt100 {


using std::ios_base;
struct vt100_base {

    // constructors for plain sequences
    vt100_base(std::string s)  : sequence(s, ios_base::ate) {}
    vt100_base(const char * s) : sequence(s, ios_base::ate) {}

    // constructor for single param (n)  e.g: \033[nA
    vt100_base(std::string s, int n, std::string ch) 
	    : sequence(s, ios_base::ate)
    {

	sequence << n << ch ;
    }

    // constructor for two params (x,y) e.g: \033[x;yH
    vt100_base(std::string s, int x, int y, std::string ch) 
	    : sequence(s, ios_base::ate)
    {

	sequence << x << ";" << y << ch ;
    }


    // copy constructor needed for ostringstream
    vt100_base(const vt100_base& v) : sequence(v.sequence.str()) {}

    std::ostringstream sequence;
};

std::ostream& operator<<(std::ostream & out, const vt100_base v)  {
    out << v.sequence.str();
    return out;
}
struct down : public vt100_base {
    down(int n=1) : vt100_base("\033[", n, "B") {}
};

struct up : public vt100_base {
    up(int n=1) : vt100_base("\033[", n, "A") {}
};

struct right : public vt100_base {
    right(int n=1) : vt100_base("\033[", n, "C") {}
};

struct left : public vt100_base {
    left(int n=1) : vt100_base("\033[", n, "D") {}
};

struct moveto : public vt100_base {
    moveto(int x, int y) : vt100_base("\033[", x, y, "H") {}
};


/ screen
static vt100_base reset("\033[0m"); // reset attributes
static vt100_base clear("\033[2J"); // clear screen
static vt100_base cls("\033c");    // clear screen cursor top left

// attributes
static vt100_base bright("\033[1m");
static vt100_base dim("\033[2m");
static vt100_base underscore("\033[4m");
static vt100_base blink("\033[5m");
static vt100_base reverse("\033[7m");
static vt100_base hidden("\033[8m");

// text colours
static vt100_base fg_black("\033[30m");
static vt100_base fg_red("\033[31m");
static vt100_base fg_green("\033[32m");
static vt100_base fg_yellow("\033[33m");
static vt100_base fg_blue("\033[34m");
static vt100_base fg_magenta("\033[35m");
static vt100_base fg_cyan("\033[36m");
static vt100_base fg_white("\033[37m");

// background colours
static vt100_base bg_black("\033[40m");
static vt100_base bg_red("\033[41m");
static vt100_base bg_green("\033[42m");
static vt100_base bg_yellow("\033[43m");
static vt100_base bg_blue("\033[44m");
static vt100_base bg_magenta("\033[45m");
static vt100_base bg_cyan("\033[46m");
static vt100_base bg_white("\033[47m");

// erasers
static vt100_base erase_eol("\033[K");
static vt100_base erase_sol("\033[1K");
static vt100_base erase_line("\033[2K");
static vt100_base erase_down("\033[J");
static vt100_base erase_up("\033[1J");

static vt100_base cursor_off("\033[?25l");
static vt100_base cursor_on ("\033[?25h");
static vt100_base cursor_home("\033[H");

} // namespace end 
Last edited on
Topic archived. No new replies allowed.