error while using template with ostream operator

Pages: 12
Hi all,

i have some issue, i'm trying to ceate class as template and use iostream operator overloading as well.
for some cause, i got some error ->
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Interval<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$Interval@H@@@Z) referenced in function "void __cdecl testIntervalInt(void)" (?testIntervalInt@@YAXXZ) Project11 C:\Users\eladb\source\repos\Project11\Project11\main.obj 1

my piceses code -
class seclration -
#ifndef INTERVAL_H
#define INTERVAL_H
#include <iostream>
using namespace std;
template <class T1>
class Interval
{

friend ostream& operator<<(ostream&, const Interval<T1>&);
private:
T1 first, second;
public:
//Interval();
Interval(T1 = 0, T1 = 0);
bool Isvalid(T1, T1);
//void printInterval(T, T) const;

//~Interval();
};

class Cpp -
template <class T1>
iostream& operator<< (ostream& out, const Interval<T1>& temp)
{
if (Isvalid(temp.first, temp.second))
out << "(" << temp.first << "," << temp.second << ")" << endl;
else
out << "Invalid" << endl;
return out;
}

please advice ,

the problem is in line 17. Fix it and the program will run perfectly.
Last edited on
what could be the problem ?
are you meaning to the distractor line ?
i deleted this line and the problem still there...
Let me have another look
A simple solution is to define the friend function within the class body. For example:

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

template < typename T > struct interval
{
    static_assert( std::is_arithmetic<T>::value, "error: not an arithmetic type" ) ;

    interval( T a, T b ) : first(a), second(b) {}

    bool valid() const { return first <= second ; }

    T first = T() ;
    T second = T() ;

    friend std::ostream& operator<< ( std::ostream& stm, interval i )
    {
        if( !i.valid() ) stm << "invalid " ;
        return stm << "interval [ " << i.first << ", " << i.second << " ]" ;
    }
};

int main()
{
    const interval<int> i( 12, 34 ) ;
    std::cout << i << '\n' ;

    interval<double> d( 9.8, 4.2 ) ;
    std::cout << d << '\n' ;
}

http://coliru.stacked-crooked.com/a/5b8d8d20b27e58db

For another way, see 'Why do I get linker errors when I use template friends?'
https://isocpp.org/wiki/faq/templates#template-friends
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
#include <iostream>

using namespace std;

template <class T1>
class Interval
{
private:
    T1 first, second;
public:
    
    Interval(T1 t1 = 0, T1 t2 = 0)
    {
        first = t1;
        second = t2;
    };
    ~Interval();
    
    bool Isvalid(T1 t1, T1 t2)
    {
        // ???
    };
    
    friend ostream& operator<< (ostream& out, const Interval<T1>& temp)
    {
        if (temp.Isvalid(temp->first, temp->second))
            out << "(" << temp.first << "," << temp.second << ")" << endl;
        else
            out << "Invalid" << endl;
        return out;
    }
    
    //void printInterval(T, T) const;
    
    //
};
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
#include <iostream>
using namespace std;


template <class T1> class Interval
{
private:
   T1 first, second;
public:
   Interval( T1 f = 0, T1 s = 0) : first( f ), second( s ) {}
   bool Isvalid() const { return first <= second; }
   template <class T2> friend ostream & operator << ( ostream &, const Interval<T2> & );
};


template <class T1> ostream & operator << ( ostream& out, const Interval<T1>& temp )
{
   if ( temp.Isvalid() ) out << "(" << temp.first << "," << temp.second << ")" << '\n';
   else                  out << "Invalid\n";
   return out;
}


int main()
{
   Interval<double> a( 1.5, 2.5 ), b( 7.0, 6.1 );
   cout << a << '\n';
   cout << b << '\n';
}
Last edited on
@edlab,

There you go friend, 3 of the best have replied in a positive, timely and helpful way for you.

Problem solved. All the best for your future.

All we need now from you is a green tick to close this off.

:)
This
1
2
3
4
5
template <class T1> class X
{
   // ...
   template <class T2> friend YYY ... ;
};

is not a very good idea unless it is a design requirement to make an unbounded set of friend functions/classes. Fatuous friendship is never a good idea.
an unbounded set of friend functions/classes


But in this instance the only friend'ed function is the operator << for an Interval<T> of some type. That is hardly "unbounded".

The choice of the word "Fatuous" was unnecessary.
Last edited on
The choice of the word "Fatuous" was unnecessary.

I assume he chose the word for the alliteration and not to offend.
> But in this instance the only friend'ed function is the operator << for an Interval<T> of some type.
> That is hardly "unbounded".

In this instance, the friend functions of Interval<X> are all the overloaded operators for every Interval<Y>.
An unbounded set of friend functions.

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
#include <iostream>
#include <typeinfo> // *** added

template < typename T1 > struct A
{
    explicit A( int v = 0 ) : v(v) {}

    private: int v = 0 ;

    template < typename T2 > friend std::ostream& operator<< ( std::ostream& stm, const A<T2>& a ) ;
};

template < typename T2 > std::ostream& operator<< ( std::ostream& stm, const A<T2>& a )
{
    stm << "\nstd::ostream& operator<< ( std::ostream& stm, const A<"
        << typeid(T2).name() << ">& )  " << a.v << '\n' ; // fine; friend

    A<int> ai(1) ;
    stm << "\taccess private member of A<int> " << ai.v << '\n' ; // also friend of A<int>
    ++ai.v ;

    A<double> ad(2) ;
    return stm << "\taccess private member of A<double> " << ad.v << '\n' ; // also friend of A<double>
}

template <> std::ostream& operator<< <void> ( std::ostream& stm, const A<void>& a )
{
    stm << "\nstd::ostream& operator<< <void> ( std::ostream& stm, const A<void>& a )  "
        << a.v << '\n' ; // fine; friend

    A<int> ai(3) ;
    stm << "\taccess private member of A<int> " << ai.v << '\n' ; // also friend of A<int>
    ++ai.v ;

    A<double> ad(4) ;
    stm << "\taccess private member of A<double> " << ad.v << '\n' ; // also friend of A<double>

    A<char> ac(5) ;
    stm << "\taccess private member of A<char> " << ac.v << '\n' ; // also friend of A<char>

    A<long> al(6) ;
    return stm << "\taccess private member of A<long> " << al.v << '\n' ; // also friend of A<long>
}

int main()
{
    A<char> ac(7) ;
    std::cout << ac ;

    A<long> al(8) ;
    std::cout << al ;

    A<void> av(9) ;
    std::cout << av ;

    struct XXX {};
    A<XXX> ax(10) ;
    std::cout << ax ;
}

http://coliru.stacked-crooked.com/a/4f9f7dfa355e4a3e
https://rextester.com/PFRV19518
Last edited on
@JLBorges, you're missing #include <typeinfo> :-)
Yes, thanks! Adding it now.
thak you all guys.
I declear and define on the Hader file, this is work !
please proceed and close this ticket.

thanks again,
Excellent!


You have to close it by giving it a green tick :)
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 Interval;
template <class T> ostream & operator << ( ostream &, const Interval<T> & );


template <class T1> class Interval
{
private:
   T1 first, second;
public:
   Interval( T1 f = 0, T1 s = 0) : first( f ), second( s ) {}
   bool Isvalid() const { return first <= second; }
   friend ostream & operator << <T1> ( ostream &, const Interval<T1>& );
};


template <class T1> ostream & operator << ( ostream& out, const Interval<T1>& temp )
{
   if ( temp.Isvalid() ) out << "(" << temp.first << "," << temp.second << ")" << '\n';
   else                  out << "Invalid\n";
   return out;
}


int main()
{
   Interval<double> a( 1.5, 2.5 ), b( 7.0, 6.1 );
   cout << a << '\n';
   cout << b << '\n';
}



One last attempt to keep declaration and definition separate, even if for templated functions they are going to end up in the same file anyway.

(And yes, I'm well aware that - for short functions - I could simply define them within the class declaration. This is just an attempt to see how separation could be effected in the case of much longer functions.)
Last edited on
Sama, sama:
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
#include <iostream>

using namespace std;

template <class T> class Interval;
template <class T> ostream & operator << ( ostream &, const Interval<T> & );


template <class T> class Interval
{
private:
   T first, second;
public:
   Interval( T f = 0, T s = 0) : first( f ), second( s ) {}
   bool Isvalid() const { return first <= second; }
   friend ostream & operator << <T> ( ostream &, const Interval<T>& );
};


template <class T> ostream & operator << ( ostream& out, const Interval<T>& temp )
{
   if ( temp.Isvalid() ) out << "(" << temp.first << "," << temp.second << ")" << '\n';
   else                  out << "Invalid\n";
   return out;
}


int main()
{
   Interval<double> a( 1.5, 2.5 ), b( 7.0, 6.1 );
   cout << a << '\n';
   cout << b << '\n';
}


(1.5,2.5)

Invalid

Program ended with exit code: 0
Confused. Other than changing the name of the template parameters (which had been left to compare with the previous "fatuous" version), what was the point of repeating the post?
Last edited on
I'm not 100% sure what borges' meant by 'fatuous friendship' other than if you have too many types gaining access via the friend functionality there is an expanding potential for the principle of data-hiding wrt private members to break down.

I even checked wikipedia an fatuous love which has interesting parallels with the unwanted intrusion, the pitfalls of love at first sight, love triangles and perhaps even std transmission. Whether borges went that far in the metaphor I don't know.

I decided not to comment at the time, because I concluded one T ( ie T or T1 or T2 alone) type was better than multiples, and fuckit, mine was clear of that hence my silence until now.

I then arranged for a green tick, upon which you came back, still showing the variety of T's, a course of action you are fully entitled to.

So I thought I would test my hypothesis that perhaps borges was concerned (infatuated perhaps?) by multiple T's.

I tested my hypothesis and there appears to be no need for extras as the result is the same. I posted accordingly.

I have no reason to believe other than speculation that my hypothesis is in line with borges adverse assessment or that you have some special reason for multiple T's.

Only you two know your motivations, reasons and criteria. Mine worked and that's all that mattered to me at the time.

That was the point of the post. Thank you for asking.

Pages: 12