Javier
Javier

Reputation: 1141

template class, friend operator << overload

I'm trying to overload the "<<" operator for a template class. I've the definition of the class in a .h file and its implementation in a .cpp file.

/tmp/ccjJIJhO.o: In function `main':
main.cpp:(.text+0xad): undefined reference to `std::basic_istream<char, std::char_traits<char> >& operator>><int>(std::basic_istream<char, std::char_traits<char> >&, FeatureVector<int>&)'
main.cpp:(.text+0xba): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& operator<< <int>(std::basic_ostream<char, std::char_traits<char> >&, FeatureVector<int> const&)'
collect2: ld returned 1 exit status

The class definition:

common.h

#include <iostream>
using namespace std;

featurevector.h

#ifndef FEATURE_VECTOR_H
#define FEATURE_VECTOR_H

#include <common.h>

template < class FEAT_TYPE >
class FeatureVector;

template < class FEAT_TYPE >
istream & operator >> (istream &, FeatureVector<FEAT_TYPE> &);

template < class FEAT_TYPE >
ostream & operator << (ostream &, const FeatureVector<FEAT_TYPE> &);

template < class FEAT_TYPE >
class FeatureVector{
    public:
        FeatureVector(int = 0);
        ...
        friend istream & operator >> <>(istream &, FeatureVector<FEAT_TYPE> & );
        friend ostream & operator << <>(ostream &, const FeatureVector<FEAT_TYPE> &);
        ...
        ~FeatureVector();

    private:
        int m_nDim;
        FEAT_TYPE * m_pFeat;
};
#endif

featurevector.cpp

#include <featurevector.h>
...
template < class FEAT_TYPE >
istream & operator >> (istream & input, FeatureVector< FEAT_TYPE> & refFeat ){

    int d;

    for(d=0; d < refFeat.getDim(); d++){
        input >> refFeat.m_pFeat[d];
    }

    return (input);
}

template < class FEAT_TYPE >
ostream & operator << (ostream & output, const FeatureVector< FEAT_TYPE > & refFeat ){

    int d;

    for(d=0; d < refFeat.getDim(); d++){
        output << refFeat.m_pFeat[d] << " ";
    }

    output << endl;

    return (output);
}
...
#include "featurevector-impl.cpp"

featurevector-impl.cpp

template class FeatureVector<int>;
//template istream & operator >> <>(istream &, FeatureVector<int> &);
//template ostream & operator << <>(ostream &, const FeatureVector<int> &);

mylib.h

#ifndef MY_LIB_H
#define MY_LIB_H
#include <featurevector.h>
#endif

main.cpp

#include <mylib.h>
#include <common.h>

int main(){
    FeatureVector<int> pFeat(10);
    cin >> (pFeat);
    cout << (pFeat);

    return (0);
}

Makefile associated with "mylib"

INC=./inc
SRC=./src
LIB=./lib
OBJ=./obj

CC=g++
CFLAGS=-O3 -Wall

mylib: $(LIB)/mylib.a
echo "mylib was created!..."

$(LIB)/mylib.a: \
$(OBJ)/featurevector.o 
    ar csr $(LIB)/mylib.a \
$(OBJ)/featurevector.o 

$(OBJ)/featurevector.o: $(SRC)/featurevector.cpp
    $(CC) -c $(CFLAGS) $(SRC)/featurevector.cpp -I$(INC)  \
    -o $(OBJ)/featurevector.o

clean:
    rm -rf $(LIB)/*.a
    rm -rf $(OBJ)/*.o

Makefile for main.cpp (the main.cpp with its Makefile are under an "app" directory)

LIB=../lib
INC=../inc
OBJ=../obj
BIN=../bin

CC=g++
CFLAGS=-O3 -Wall
LFLAGS=-lmylib -lm

[email protected]: $(LIB)/mylib.a [email protected]
    cd ..; make; cd app;
$(CC) $(CFLAGS) [email protected] -o $(BIN)/$@ -I$(INC) -L$(LIB) $(LFLAGS)

clean:
    rm -rf $(BIN)/*

Upvotes: 3

Views: 10895

Answers (5)

CH Liu
CH Liu

Reputation: 1884

According to this, you have to make the function known as template in your class definition.

class.h

#include <iostream>
using std::ostream;

template <typename T>
class A {
  public:
    ...

    template <typename J> // <-- CAUTION!
    friend ostream &operator<<(ostream &output, const A<J> &a);
};

class.cpp

#include "class.h"
...
template <typename T>
ostream &operator<<(ostream &output, const A<T> &a) {
  // Your implementation
  return output;
}

...
template ostream &operator<<(ostream &output, const A<int> &a);
template ostream &operator<<(ostream &output, const A<float> &a);

If the line template <typename J> is removed, the compilation error "underfined reference" comes.

Upvotes: 5

Steve M
Steve M

Reputation: 8516

featurevector-impl.cpp is incorrect. Explicit template instantiations look like this:

template class FeatureVector<int>;

Since the operators aren't members, they must also be explicitly instantiated:

template istream & operator >> <>(istream &, FeatureVector<int> &);

I don't recommend splitting up your template definitions like this, though, unless you're really keen on micromanaging which specific classes will work with your template (which kind of goes against the spirit of using a template).

Upvotes: 0

Roger Pate
Roger Pate

Reputation:

Don't make it so complicated:

template<class FEAT_TYPE>
struct FeatureVector {
  FeatureVector(int = 0);

  friend std::istream& operator>>(std::istream &s, FeatureVector &x) {
    for(int d = 0; d < x.getDim(); d++) {
      s >> x.m_pFeat[d];
    }
    return s;
  }

  friend std::ostream& operator<<(std::ostream &s, FeatureVector const &x) {
    // since you're terminating with " " rather than separating:
    copy(x.m_pFeat, x.m_pFeat + x.getDim(), ostream_iterator<FEAT_TYPE>(s, " "));
    s << endl;
    return s;
  }

  //...

Upvotes: 0

John Dibling
John Dibling

Reputation: 101456

Your posted error code says that it is operator>> that is throwing an unresolved external error, not operator<<. In addition, your code won't compile because there is no convert constructor on myClass taking an int. So you have not posted the correct code.

But this works:

#include <iostream>
using namespace std;

template < class T >
class myClass;

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

template < class T >
class myClass{
    public:
        myClass(int) {}
        friend ostream & operator << <>(ostream &, const myClass<T> &);

    private:
        T m_Data;
};

template < class T >
ostream & operator << (ostream & out, const myClass<T> & refClass){
    out << refClass.m_Data << endl;
    return (out);
}

myClass<int>;
myClass<float>;



int main(int argc, char **argv){
    myClass<int> test(5);
    cout << test;
    return 0;
}

Upvotes: 1

Related Questions