operator<< with template class doesn't work

Discussion in 'C++' started by Wolfnoliir, Aug 30, 2009.

  1. Wolfnoliir

    Wolfnoliir Guest

    Hi,

    I am trying to output a template class to 'cout' but my code doesn't
    compile; here is gcc's error message:

    /tmp/ccnNaceV.o: In function `main':
    main.cpp:(.text+0x6d): undefined reference to
    `std::basic_ostream<char, std::char_traits<char> >& operator<<
    <char>(std::basic_ostream<char, std::char_traits<char> >&,
    Sudoku<char>&)'
    collect2: ld returned 1 exit status

    and here is the code:

    157 template<class T>
    158 ostream& operator<<(ostream& os, const Sudoku<T>& s)
    159 {
    160 for (char i=0; i < s.size; i++)
    161 {
    162 for (char j=0; j < s.size; j++)
    163 {
    164 if ( s.is_true(i, j) && HAS_BOLD )
    165 {
    166 os << "\033[1m" << s.get(i,j) << "\033[0m\t";
    167 }
    168 else
    169 os << s.matrix->at(i,j) << "\t";
    170 }
    171 os << "\n";
    172 }
    173 return os;
    174 }
    175
    176 int main()
    177 {
    178 Sudoku<char> s;
    179 //cout << s;
    180 operator<<(cout, s);
    181 return 0;
    182 }

    I have declared
    friend ostream& operator<<(ostream& os, Sudoku<T2>& s);
    in the template class Sudoku.

    Thanks.
    Wolfnoliir, Aug 30, 2009
    #1
    1. Advertising

  2. Wolfnoliir wrote:
    > [..] and here is the code:
    >
    > 157 template<class T>
    > 158 ostream& operator<<(ostream& os, const Sudoku<T>& s)
    >
    > friend ostream& operator<<(ostream& os, Sudoku<T2>& s);


    Read the two declarations carefully and see if you can notice any
    difference.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Aug 30, 2009
    #2
    1. Advertising

  3. Wolfnoliir

    Francesco Guest

    On 30 Ago, 19:12, Wolfnoliir <> wrote:
    > Hi,
    >
    > I am trying to output a template class to 'cout' but my code doesn't
    > compile; here is gcc's error message:
    >
    > /tmp/ccnNaceV.o: In function `main':
    > main.cpp:(.text+0x6d): undefined reference to
    > `std::basic_ostream<char, std::char_traits<char> >& operator<<
    > <char>(std::basic_ostream<char, std::char_traits<char> >&,
    > Sudoku<char>&)'
    > collect2: ld returned 1 exit status
    >
    > and here is the code:
    >
    > 157 template<class T>
    > 158 ostream& operator<<(ostream& os, const Sudoku<T>& s)
    > 159 {
    > 160 for (char i=0; i < s.size; i++)
    > 161 {
    > 162 for (char j=0; j < s.size; j++)
    > 163 {
    > 164 if ( s.is_true(i, j) && HAS_BOLD )
    > 165 {
    > 166 os << "\033[1m" << s.get(i,j) << "\033[0m\t";
    > 167 }
    > 168 else
    > 169 os << s.matrix->at(i,j) << "\t";
    > 170 }
    > 171 os << "\n";
    > 172 }
    > 173 return os;
    > 174 }
    > 175
    > 176 int main()
    > 177 {
    > 178 Sudoku<char> s;
    > 179 //cout << s;
    > 180 operator<<(cout, s);
    > 181 return 0;
    > 182 }
    >
    > I have declared
    > friend ostream& operator<<(ostream& os, Sudoku<T2>& s);
    > in the template class Sudoku.
    >
    > Thanks.


    Well, to be precise, it compiles. Your problem is that it doesn't
    link. Please post sufficient, self contained code that reproduces the
    same problem, so that people can copy, paste and test it to help you,
    with reference to http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.8

    Cheers,
    Francesco
    Francesco, Aug 30, 2009
    #3
  4. Wolfnoliir

    Wolfnoliir Guest

    Victor Bazarov wrote:
    > Wolfnoliir wrote:
    >> [..] and here is the code:
    >>
    >> 157 template<class T>
    >> 158 ostream& operator<<(ostream& os, const Sudoku<T>& s)
    >>
    >> friend ostream& operator<<(ostream& os, Sudoku<T2>& s);

    >
    > Read the two declarations carefully and see if you can notice any
    > difference.
    >
    > V


    If you are talking about the T2 instead of T; I had to make that
    change because to was already declared as the template class of
    the Sudoku class so I had to change it.
    I am quite shure this is not the origin of the problem.

    but thanks.
    Wolfnoliir, Aug 30, 2009
    #4
  5. Wolfnoliir

    Wolfnoliir Guest

    Francesco wrote:
    > Well, to be precise, it compiles. Your problem is that it doesn't
    > link. Please post sufficient, self contained code that reproduces the
    > same problem, so that people can copy, paste and test it to help you,
    > with reference to http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.8
    >
    > Cheers,
    > Francesco


    compiled with
    g++ main.cpp -o main -W -Wall

    Here is the entire code:


    #include <iostream>
    #include <assert.h>
    #include <math.h>

    #define HAS_BOLD 1

    using namespace std;

    template<class T> class SimpleMatrix
    {
    public:
    SimpleMatrix(int x, int y) : sizex(x), sizey(y)
    {
    matrix = new T[x*y];

    }
    T& at(int x, int y)
    {
    assert( x < sizex );
    assert( y < sizey );
    return &matrix[x*sizey + sizex];
    }
    void set(int x, int y, T s)
    {
    assert( x < sizex );
    assert( y < sizey );
    this.at(x, y) = s;
    }
    void set_all(T s)
    {
    int size = sizex*sizey;
    for (int i=0; i<size; i++)
    {
    matrix = s;
    }
    }

    private:
    T *matrix;
    int sizex;
    int sizey;
    };


    template<class T> class Sudoku
    {
    template<class T2>
    friend ostream& operator<<(ostream& os, Sudoku<T2>& s);
    public:
    Sudoku() : size(9)
    {
    matrix = new SimpleMatrix<T>(9,9);
    truthMatrix = new SimpleMatrix<char>(9,9);

    sqrtSize = (T)sqrt(size);
    assert( (double)sqrtSize == sqrt(size) );

    //T must be a signed type:
    assert( (T)(-1) == (int)(-1) );
    matrix->set_all(-1);
    truthMatrix->set_all(0);
    }


    T get(T x, T y)
    {
    return *matrix->at(x,y);
    }

    char is_true(T x, T y)
    {
    return *truthMatrix->at(x,y);
    }
    char set(T x, T y, T s)
    {
    assert( x < size );
    assert( y < size );

    if ( !(is_true(x, y)) )
    matrix->set(x, y, s);
    else
    return -1;
    return 0;
    }
    void set_as_true(T x, T y, T s)
    {
    matrix->set(x, y, s);
    truthMatrix->set(x, y, 1);
    }

    T get_section(T x)
    //sections go from 1 to $size
    {
    return (T)ceil( (double)x / (double)sqrtSize );
    }

    T* test_coherence(T x, T y)
    {
    //check lines and columns:
    for (T i=0; i < size; i++)
    {
    if ( matrix->at(i,y) == matrix->at(x,y) && &matrix->at(i,y) !=
    &matrix->at(x,y) )
    {
    return &matrix->at(i,y);
    }
    else if ( matrix->at(x,i) == matrix->at(x,y) && &matrix->at(x,i) !=
    &matrix->at(x,y) )
    {
    return &matrix->at(x,i);
    }
    }
    //check submatrix:
    T sx = get_section(x);
    T sy = get_section(y);
    T minx = (sx-1)*sqrtSize;
    T miny = (sy-1)*sqrtSize;
    T maxx = sx*sqrtSize;
    T maxy = sy*sqrtSize;
    for (T i=minx; i < maxx; i++)
    {
    for (T j=miny; j < maxy; j++)
    {
    if (matrix->at(i,j) == matrix->at(x,y) && &matrix->at(x,y) !=
    &matrix->at(i,j))
    {
    return &matrix->at(i,j);
    }
    }
    }
    return (T)(-1);
    }

    private:
    SimpleMatrix<T> *matrix;
    SimpleMatrix<char> *truthMatrix;
    T size;
    T sqrtSize;


    void set_matrix(T* matrix, T c)
    {
    for (T i=0; i < size; i++)
    {
    for (T j=0; j<size; j++)
    {
    matrix->at(i,j) = c;
    }
    }
    }

    };
    /*
    istream& operator>>(istream& is, Sudoku<T>& s)
    {
    return NULL;
    }
    */

    template<class T>
    ostream& operator<<(ostream& os, const Sudoku<T>& s)
    {
    for (char i=0; i < s.size; i++)
    {
    for (char j=0; j < s.size; j++)
    {
    if ( s.is_true(i, j) && HAS_BOLD )
    {
    os << "\033[1m" << s.get(i,j) << "\033[0m\t";
    }
    else
    os << s.matrix->at(i,j) << "\t";
    }
    os << "\n";
    }
    return os;
    }

    int main()
    {
    Sudoku<char> s;
    //cout << s;
    operator<<(cout, s);
    return 0;
    }
    Wolfnoliir, Aug 30, 2009
    #5
  6. Wolfnoliir

    Jerry Coffin Guest

    In article <4a9abdb8$0$31038$>,
    says...
    >
    > Victor Bazarov wrote:
    > > Wolfnoliir wrote:
    > >> [..] and here is the code:
    > >>
    > >> 157 template<class T>
    > >> 158 ostream& operator<<(ostream& os, const Sudoku<T>& s)
    > >>
    > >> friend ostream& operator<<(ostream& os, Sudoku<T2>& s);

    > >
    > > Read the two declarations carefully and see if you can notice any
    > > difference.
    > >
    > > V

    >
    > If you are talking about the T2 instead of T; I had to make that
    > change because to was already declared as the template class of
    > the Sudoku class so I had to change it.
    > I am quite shure this is not the origin of the problem.


    Look at it again, and see if you don't see another difference -- a
    word (a keyword) that's present in one, but not the other...

    --
    Later,
    Jerry.
    Jerry Coffin, Aug 30, 2009
    #6
  7. Wolfnoliir

    Wolfnoliir Guest

    Jerry Coffin wrote:
    > In article <4a9abdb8$0$31038$>,
    > says...
    >> Victor Bazarov wrote:
    >>> Wolfnoliir wrote:
    >>>> [..] and here is the code:
    >>>>
    >>>> 157 template<class T>
    >>>> 158 ostream& operator<<(ostream& os, const Sudoku<T>& s)
    >>>>
    >>>> friend ostream& operator<<(ostream& os, Sudoku<T2>& s);
    >>> Read the two declarations carefully and see if you can notice any
    >>> difference.
    >>>
    >>> V

    >> If you are talking about the T2 instead of T; I had to make that
    >> change because to was already declared as the template class of
    >> the Sudoku class so I had to change it.
    >> I am quite shure this is not the origin of the problem.

    >
    > Look at it again, and see if you don't see another difference -- a
    > word (a keyword) that's present in one, but not the other...
    >


    I indeed forgot the 'const'. That was a pretty stupid mistake.
    I think I can now solve my problem by adding a few other 'const's
    that I forgot.

    Thank you.
    Wolfnoliir, Aug 30, 2009
    #7
  8. Wolfnoliir

    Francesco Guest

    On 30 Ago, 20:51, Wolfnoliir <> wrote:
    > Jerry Coffin wrote:
    > > In article <4a9abdb8$0$31038$>,
    > > says...
    > >> Victor Bazarov wrote:
    > >>> Wolfnoliir wrote:
    > >>>> [..] and here is the code:

    >
    > >>>> 157 template<class T>
    > >>>> 158 ostream& operator<<(ostream& os, const Sudoku<T>& s)

    >
    > >>>> friend ostream& operator<<(ostream& os, Sudoku<T2>& s);
    > >>> Read the two declarations carefully and see if you can notice any
    > >>> difference.

    >
    > >>> V
    > >> If you are talking about the T2 instead of T; I had to make that
    > >> change because to was already declared as the template class of
    > >> the Sudoku class so I had to change it.
    > >> I am quite shure this is not the origin of the problem.

    >
    > > Look at it again, and see if you don't see another difference -- a
    > > word (a keyword) that's present in one, but not the other...

    >
    > I indeed forgot the 'const'. That was a pretty stupid mistake.
    > I think I can now solve my problem by adding a few other 'const's
    > that I forgot.
    >
    > Thank you.


    Fine, now that you have solved that issue, please note that there are
    several other points you can fix/improve:
    - the C-style casts
    - the use of #define
    - the possible memory leak due to your use of operator new
    - the test for signed types (use the functions found in <limits>
    instead)

    Refer to the FAQ I linked and you'll find solutions to most of your
    issues, along with their rationales.

    Keep improving your code,
    cheers,
    Francesco
    Francesco, Aug 30, 2009
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page