I am testing a program in C++ Templates (from the Deitel Textook) and I have the typical three files:

Array.h:

// Exercise 14.7 Solution: Array.h
// Class template Array definition.
#ifndef ARRAY1_H
#define ARRAY1_H

#include <iostream>
using namespace std;

template < typename elementType, int numberOfElements >
class Array
{

public:
   Array(); // default constructor
   ~Array(); // destructor
   int getSize() const; // return size
   elementType &operator[]( int ); // subscript operator
   void inputArray(); // input the array elements
   void outputArray() const; // output the array elements

private:
   elementType elements[ numberOfElements ]; // array of elements
   static int arrayCount; // # of Arrays instantiated
};

#endif

Array.cc:

// Exercise 14.7 Solution: Array.h
// Class template Array function definitions.
#include "Array.h"
#include <iostream> 
using namespace std;

// define static data member at file scope
template < typename elementType, int numberOfElements >
int Array< elementType, numberOfElements >::arrayCount = 0; // no objects

// default constructor for class Array
template < typename elementType, int numberOfElements >
Array< elementType, numberOfElements >::Array()
{
   arrayCount++; // count one more object

   // initialize array
   for ( int i = 0; i < numberOfElements; i++ )
      elements[ i ] = elementType();                
}

// destructor for class Array
template < typename elementType, int numberOfElements >
Array< elementType, numberOfElements >::~Array() 
{
   arrayCount--;
}

// get the size of the array
template < typename elementType, int numberOfElements >
int Array< elementType, numberOfElements >::getSize() const 
{
   return numberOfElements;
}

// overloaded subscript operator
template < typename elementType, int numberOfElements >
elementType &Array< elementType, numberOfElements >:: 
   operator[]( int subscript )
{
   // check for subscript
   assert( 0 <= subscript && subscript < numberOfElements ); 
   return elements[ subscript ]; // reference return creates lvalue
}

// input values for entire array.
template < typename elementType, int numberOfElements >
void Array< elementType, numberOfElements >::inputArray()
{
   // get values of array from user
   for ( int i = 0; i < numberOfElements; i++ )
      cin >> elements[ i ];
}

// Output the array values
template < typename elementType, int numberOfElements >
void Array< elementType, numberOfElements >::outputArray() const
{
   int i;

   // output array
   for ( i = 0; i < numberOfElements; i++ ) 
   {
      cout << elements[ i ] << ' ';

      // form rows for output
      if ( ( i + 1 ) % 10 == 0 )
         cout << '\n';
   } // end for

   if ( i % 10 != 0 )
      cout << '\n';
}

ArrayTest.cc:

// Exercise 14.7 Solution: Ex14_07.cpp
#include <iostream>
#include <string>
#include "Array.h"
using namespace std;

int main()
{
   Array< int, 5 > intArray; // create intArray object      

   // initialize intArray with user input values
   cout << "Enter " << intArray.getSize() << " integer values:\n";
   intArray.inputArray();

   // output intArray
   cout << "\nThe values in intArray are:\n";
   intArray.outputArray();

   Array< string, 7 > stringArray; // create stringArray  

   // initialize stringArray with user input values
   cout << "\nEnter " << stringArray.getSize()
      << " one-word string values:\n";
   stringArray.inputArray();

   // output stringArray
   cout << "\nThe values in the stringArray are:\n";
   stringArray.outputArray();
  
}

I then did the following:

g++ Array.h (No Syntax errors)

g++ Array.cc -c (No Syntax errors)

g++ -o Array ArrayTest.cc Array.o - results in the following run-time errors:

Undefined                       first referenced
 symbol                             in file
Array<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 7>::inputArray()/var/tmp//ccFE6W6e.o
Array<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 7>::getSize() const/var/tmp//ccFE6W6e.o
Array<int, 5>::inputArray()         /var/tmp//ccFE6W6e.o
Array<int, 5>::outputArray() const  /var/tmp//ccFE6W6e.o
Array<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 7>::~Array()/var/tmp//ccFE6W6e.o
Array<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 7>::Array()/var/tmp//ccFE6W6e.o
Array<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 7>::outputArray() const/var/tmp//ccFE6W6e.o
Array<int, 5>::getSize() const      /var/tmp//ccFE6W6e.o
Array<int, 5>::Array()              /var/tmp//ccFE6W6e.o
Array<int, 5>::~Array()             /var/tmp//ccFE6W6e.o
ld: fatal: Symbol referencing errors. No output written to Array
collect2: ld returned 1 exit status

I would appreciate any help in making sense of the above errors.

Thank you!
sciprog1

Edited 5 Years Ago by sciprog1: n/a

I think you may experience link errors with your current setup.

You need to have the code inside the header file for templates (no source file, header only).

Truthfully you can include the .cpp file at the end of the .h file, but if you're using Visual Studio you will need to exclude the .cpp file from the solution to do that, and it's not worth the trouble at all. For G++ I'm not sure how that would work.

Hello pesudorandom,

Thank you for the reply! Yes, it works when I include the Array.h and Array.cc programs in Array.h. Just wondering what makes it so different for templates that it has to be this way?

Thank you!
sciprog1

Hello pseudorandom,

Thanks a lot! That was very helpful!

Regards,
sciprog1

Not to interject now that this is solved, but give chapter 35 of the C++ FAQ (particularly question 12 a read. It's one of the clearer explanations I've run across.

This question has already been answered. Start a new discussion instead.