Thread: templates, unresolved external error

  1. #1
    Registered User
    Join Date
    Dec 2003
    Posts
    167

    templates, unresolved external error

    error:

    Error: Unresolved external 'Array<int, 6>::~Array<int, 6>()' referenced from C:\DOCUMENTS AND SETTINGS\KELVIN POMPEY\CBPROJECT\ARRAYTEMPLATE\WINDOWS\DEBUG_BUILD \MAIN.OBJ

    Code:
     
    
    // Fig. 8.4: array1.h
    // Simple class Array (for integers)
    #ifndef ARRAY1_H
    #define ARRAY1_H
    
    #include <iostream>
    
    using std::ostream;
    using std::istream;
    
    template <class T, int numberOfElements = 10>
    class Array {
       friend ostream &operator<<( ostream &, const Array<T,numberOfElements> & );
       friend istream &operator>>( istream &, Array<T,numberOfElements> & );
    public:
       Array<T,numberOfElements>();                   // default constructor
       Array( const Array<T,numberOfElements> & );              // copy constructor
       ~Array<T,numberOfElements>();                            // destructor
       int getSize() const;                 // return size
       const Array<T,numberOfElements> &operator=( const Array<T,numberOfElements> & ); // assign arrays
       bool operator==( const Array<T,numberOfElements> & ) const;  // compare equal
    
       // Determine if two arrays are not equal and
       // return true, otherwise return false (uses operator==).
       bool operator!=( const Array<T,numberOfElements> &right ) const
          { return ! ( *this == right ); }
    
       T &operator[]( int );              // subscript operator
       const T &operator[]( int ) const;  // subscript operator
       static int getArrayCount();          // Return count of
                                            // arrays instantiated.
    private:
       int size; // size of the array
       T *ptr; // pointer to first element of array
       static int arrayCount;  // # of Arrays instantiated
    };
    
    #endif
    Code:
     
    #include <iostream>
    
    using std::cout;
    using std::endl;
    
    #include "Array1.h"
    
    int main( int argc, char * argv[] )
    {
      Array<int, 6 > numbers;
    
    
      return 0;
    }
    Anyone have an idea of what im doing wrong? Just learning about templates but my book doesn't seem doesn't seem to cover the topic comprehensively.
    silk.odyssey

  2. #2
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Where did you put the implementation? You will have problems if they are in a separate cpp. Either put it in the h file or put it in an "inl" file and #include the inl file at the bottom of the header right before #endif
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  3. #3
    Registered User
    Join Date
    Dec 2003
    Posts
    167
    Here's the implementation:

    Code:
     
    // Fig 8.4: array1.cpp
    // Member function definitions for class Array
    #include <iostream>
    
    using std::cout;
    using std::cin;
    using std::endl;
    
    #include <iomanip>
    
    using std::setw;
    
    #include <cstdlib>
    #include <cassert>
    #include "array1.h"
    
    // Initialize static data member at file scope
    template <class T, int numberOfElements>
    int Array< T,numberOfElements>::arrayCount = 0;   // no objects yet
    
    // Default constructor for class Array (default size 10)
    template <class T, int numberOfElements >
    Array<T,numberOfElements>::Array()
    {
       size = ( numberOfElements > 0 ? numberOfElements : 10 );
       ptr = new T[ size ]; // create space for array
       assert( ptr != 0 );    // terminate if memory not allocated
       ++arrayCount;          // count one more object
    
       for ( int i = 0; i < size; i++ )
          ptr[ i ] = 0;          // initialize array
    }
    
    // Copy constructor for class Array
    // must receive a reference to prevent infinite recursion
    template <class T, int numberOfElements >
    Array<T,numberOfElements>::Array( const Array<T,numberOfElements> &init ) : size( init.size )
    {
       ptr = new T[ size ]; // create space for array
       assert( ptr != 0 );    // terminate if memory not allocated
       ++arrayCount;          // count one more object
    
       for ( int i = 0; i < size; i++ )
          ptr[ i ] = init.ptr[ i ];  // copy init into object
    }
    
    // Destructor for class Array
    template <class T, int numberOfElements>
    Array<T,numberOfElements>::~Array()
    {
       delete [] ptr;            // reclaim space for array
       --arrayCount;             // one fewer objects
    }
    
    // Get the size of the array
    template <class T, int numberOfElements>
    int Array<T,numberOfElements>::getSize() const { return size; }
    
    // Overloaded assignment operator
    // const return avoids: ( a1 = a2 ) = a3
    template <class T, int numberOfElements>
    const Array<T,numberOfElements> &Array<T,numberOfElements>::operator=( const Array<T,numberOfElements> &right )
    {
       if ( &right != this ) {  // check for self-assignment
    
          // for arrays of different sizes, deallocate original
          // left side array, then allocate new left side array.
          if ( size != right.size ) {
             delete [] ptr;         // reclaim space
             size = right.size;     // resize this object
             ptr = new T[ size ]; // create space for array copy
             assert( ptr != 0 );    // terminate if not allocated
          }
    
          for ( int i = 0; i < size; i++ )
             ptr[ i ] = right.ptr[ i ];  // copy array into object
       }
    
       return *this;   // enables x = y = z;
    }
    
    // Determine if two arrays are equal and
    // return true, otherwise return false.
    template <class T, int numberOfElements>
    bool Array<T,numberOfElements>::operator==( const Array<T,numberOfElements> &right ) const
    {
       if ( size != right.size )
          return false;    // arrays of different sizes
    
       for ( int i = 0; i < size; i++ )
          if ( ptr[ i ] != right.ptr[ i ] )
             return false; // arrays are not equal
    
       return true;        // arrays are equal
    }
    
    // Overloaded subscript operator for non-const Arrays
    // reference return creates an lvalue
    template <class T, int numberOfElements>
    T &Array<T,numberOfElements>::operator[]( int subscript )
    {
       // check for subscript out of range error
       assert( 0 <= subscript && subscript < size );
    
       return ptr[ subscript ]; // reference return
    }
    
    // Overloaded subscript operator for const Arrays
    // const reference return creates an rvalue
    template <class T, int numberOfElements>
    const T &Array<T,numberOfElements>::operator[]( int subscript ) const
    {
       // check for subscript out of range error
       assert( 0 <= subscript && subscript < size );
    
       return ptr[ subscript ]; // const reference return
    }
    
    // Return the number of Array objects instantiated
    // static functions cannot be const
    template <class T, int numberOfElements>
    int Array<T,numberOfElements>::getArrayCount() { return arrayCount; }
    
    // Overloaded input operator for class Array;
    // inputs values for entire array.
    template <class T, int numberOfElements>
    istream &operator>>( istream &input, Array<T,numberOfElements> &a )
    {
       for ( int i = 0; i < a.size; i++ )
          input >> a.ptr[ i ];
    
       return input;   // enables cin >> x >> y;
    }
    
    // Overloaded output operator for class Array
    template <class T, int numberOfElements>
    ostream &operator<<( ostream &output, const Array<T,numberOfElements> &a )
    {
       int i;
    
       for ( i = 0; i < a.size; i++ ) {
          output << setw( 12 ) << a.ptr[ i ];
    
          if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
             output << endl;
       }
    
       if ( i % 4 != 0 )
          output << endl;
    
       return output;   // enables cout << x << y;
    }
    I'm not familiar with "inl" files so could you tell me what they are about and is your suggestion the only solution?
    silk.odyssey

  4. #4
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    inl stands for inline. Basically the same as putting all the code in the h but just doesn't clutter things as much. I don't know any compilers that support the 'export' keyword at present. That would be the only other way to do it I believe.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  5. #5
    Registered User
    Join Date
    Dec 2003
    Posts
    167
    Well I have the microsoft visual c++ toolkit also. How would the export keyword work. If it doesn't I'll try your other solution.
    silk.odyssey

  6. #6
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    You can read here about it:

    http://www.comeaucomputing.com/4.0/d...an/export.html

    But I don't think VC++ .NET 2003 supports it. GCC doesn't yet either I believe.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  7. #7
    Registered User
    Join Date
    Dec 2003
    Posts
    167
    Your solution works but I've found another problem. When I try call the overloaded stream insertion operator with an array object I get an unresolved error. Also some of the errors from g++ suggests that the overloaded operators are not template functions. Could this be the problem?
    silk.odyssey

  8. #8
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Is the insertion operator implementation in your header? I don't really see any problems with it how it is. In fact, I opened up VC6 and threw all your code in a project and it compiled and ran fine. My main looked like this:

    Code:
      int main( int argc, char * argv[] )
      {
        Array<int, 6 > numbers;
      
        cin >> numbers;
      
        cout << numbers;
      
        return 0;
      }
    I simply copy and pasted your .cpp file to the .h file right before the #endif
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  9. #9
    Registered User
    Join Date
    Dec 2003
    Posts
    167
    Hmmm that's interesting. What I did was include the array1.cpp file right before the endif of the header file.
    silk.odyssey

  10. #10
    Registered User
    Join Date
    Dec 2003
    Posts
    167
    I tried throwing the implementation code in the header file like you did but I have the same problem.

    Here's the error message from the vc compiler.

    /out:main.exe
    main.obj
    main.obj : 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 Array<int,6> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABV?$Array@H$05@@@Z) referenced in function _main
    main.exe : fatal error LNK1120: 1 unresolved externals
    silk.odyssey

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how do you resolve this error?
    By -EquinoX- in forum C Programming
    Replies: 32
    Last Post: 11-05-2008, 04:35 PM
  2. Errors including <windows.h>
    By jw232 in forum Windows Programming
    Replies: 4
    Last Post: 07-29-2008, 01:29 PM
  3. file reading
    By gunghomiller in forum C++ Programming
    Replies: 9
    Last Post: 08-07-2007, 10:55 PM
  4. Using VC Toolkit 2003
    By Noobwaker in forum Windows Programming
    Replies: 8
    Last Post: 03-13-2006, 07:33 AM
  5. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM