Issues on using operator<< for templates

Hello,

I'm new in using templates and also overloaded operators for them. This is my simple code. I tried to write an operator<< for the type T, but faced some odd error!

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
#include <iostream>
using namespace std;

template<class T> class S {
        T val;
public:
    S<T>(T v) { val = v; }
};

//----------------------------

template <class T> ostream& operator<<(ostream& os, T& to) {
    return (os << to);
}

//------------------------------------

template <class T> void write_val(T& t) {
    cout << t << endl;
}

//---------------------------

int main()
{
    S<int> s1(5);
    write_val(s1);

    return 0;
}


The error:

Unhandled exception at 0x00EEC529 in test3.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00342F8C)

The ostream operator is said to be a recursive call that calls itself forever until the process eats up the call stack.
But how to solve that problem?

Last edited on
Thanks :D
Last edited on
I didn't understand what you said. I'm not a native speaker of English.
But about tags, there are some problems when creating a new topic such as: tags don't work, preview feature doesn't work and so on. These problems occur often. At the beginning these occurred for me but when editing I could use them properly. so I made the question clear for better reading.
The ostream operator is said to be a recursive call that calls itself forever until the process eats up the call stack.
But how to solve that problem?


For this particular problem, you want to implement operator<< in terms of your type S.

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
#include <iostream>
using namespace std;

template<class T> class S {
        T val;
public:
    S<T>(T v) { val = v; }
    
    friend ostream& operator<<(ostream&os, const S& to) {
        return os << to.val;
    }
};


template <class T> void write_val(T& t) {
    cout << t << endl;
}

//---------------------------

int main()
{
    S<int> s1(5);
    write_val(s1);

    return 0;
}
Thanks for your reply.
How to solve the problem without using friend? I'm not used to it.
And in:
1
2
3
friend ostream& operator<<(ostream&os, const S& to) {
        return os << to.val;
    }

Why not: ...(ostream&os, const T& to) { ... please? Both T and S are user-defined types and new.
How to solve the problem without using friend? I'm not used to it.


Given that there is no way for any function outside of your class to access its private members, you must supply that access, either through a member function or the use of friend.

Why not: ...(ostream&os, const T& to) { ... please? Both T and S are user-defined types and new.

There may be some confusion here. Within the class T refers to the type S is instantiated with. In your parameterized functions outside the class, T refers to the type the functions are called with. They are not the same.

So, if you were to use T& inside the class definition and you instantiated the class with type int (as your example does in main) then you would be defining an overload on type int& for operator<< when a perfectly adequate overload already exists, since int is a built-in type.

Given that there is no way for any function outside of your class to access its private members, you must supply that access, either through a member function or the use of friend.


But that operator is inside the class not outside of it. What if we make val public?

Within the class T refers to the type S is instantiated with.

I read it many times but couldn't understand!

The matter is somewhat complex. I'm reading the book of Mr. Stroustrup which seems to be hard for beginners.
Last edited on
But that operator is inside the class not outside of it. What if we make val public?

That operator is not a member of the class, so it doesn't have access to variables and methods that do not have a public access level. I only defined it inside the class, because it is easier to supply the definition there than outside the class.

Making val public would also work.

Thanks for your comments.

I only defined it inside the class

How do you define that operator outside the class for that code please?


if you were to use T& inside the class definition and you instantiated the class with type int (as your example does in main) then you would be defining an overload on type int& for operator<< when a perfectly adequate overload already exists, since int is a built-in type.


Would you write an example for that use of int&s?
Most of the types I use are built-in types, such as: int, double, char...

Last edited on
How do you define that operator outside the class for that code please?


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
#include <iostream>
using namespace std;

template<class T> class S {
    T val;
public:
    S<T>(T v) { val = v; }

    template <class U>
    friend ostream& operator<<(ostream&os, const S<U>& to);
};

template <class T>
ostream& operator<<(ostream&os, const S<T>& to) {
    return os << to.val;
}

template <class T> void write_val(T& t) {
    cout << t << endl;
}

//---------------------------

int main()
{
    S<int> s1(5);
    write_val(s1);

    return 0;
}


Would you write an example for that use of int&s?

The point was to avoid it in the context of overloading operator<< with std::ostream.
1
2
template <class U>
    friend ostream& operator<<(ostream&os, const S<U>& to);


This part seems to me not required.
What is the need for it please?
This part seems to me not required.

It's not. You could define the friend function in the class.

(Or use this also ugly alternative:)

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
#include <iostream>
using namespace std;

template <class T> class S;

template <class T>
ostream& operator<<(ostream&os, const S<T>& to) {
    return os << to.val;
}

template<class T> class S {
    T val;
public:
    S<T>(T v) { val = v; }

    friend ostream& operator<<<T>(ostream&os, const S<T>& to);
};


template <class T> void write_val(T& t) {
    cout << t << endl;
}

//---------------------------

int main()
{
    S<int> s1(5);
    write_val(s1);

    return 0;
}
for extra credit, you can use template argument deduction in that declaration to omit the first T and injected template name to omit the second T

 
    friend ostream& operator<<<>(ostream& os, const S& to);

(see also http://en.cppreference.com/w/cpp/language/friend#Template_friend_operators )
Thank you very much guys.
Topic archived. No new replies allowed.