Mark Berube
Mark Berube

Reputation: 204

What is wrong with this template program?

I've been trying to learn templates in C++ but I'm getting a little confused with what I'm doing wrong. I was told how to declare friend templates on a FAQ about templates and I had to do that with the overloaded operators but it seems to be giving me trouble telling me I have an invalid amount of arguments(I should have 2) in my Array.cpp. Is there any way I could fix this while keeping my operators. Also, is the simple main file the correct syntax for the templates?

Thank you.

Array.h:

#ifndef ARRAY_H
#define ARRAY_H
#include <stdexcept>
#include <iostream>
using namespace std;

template<typename T> class Array;
template<typename T> ostream &operator<<( ostream &, const Array<T> & );
template<typename T> istream &operator>>( istream &, Array<T> & );

template< typename T >
class Array
{


    friend ostream &operator<< <> ( ostream &, const Array<T> & );
    friend istream &operator>> <> ( istream &, Array<T> & );

 public:
    Array(  int = 10 ); 

    Array( const Array & ); 

    ~Array();

    int getSize() const; 

    const Array &operator=( const Array & ); 

    bool operator==( const Array & ) const; 


    bool operator!=( const Array &right ) const  
    { 
        return ! ( *this == right ); 
    }


    T &operator[]( T );              


    T operator[]( T ) const;  

 private:

    int size; 

    T *ptr;

};

#endif

Array.cpp

#include <iostream>
#include <iomanip>
#include <cstdlib> // exit function prototype
#include "Array.h" // Array class definition
using namespace std;

template< typename T >
Array<T>::Array( int arraySize )
{

    if ( arraySize > 0 )
        size = arraySize;
    else 
        throw invalid_argument( "Array size must be greater than 0" );

    ptr = new T[ size ]; 

    for ( int i = 0; i < size; ++i )
        ptr[ i ] = 0;

}

template< typename T >
Array<T>::Array( const Array &arrayToCopy ) 
   : size( arrayToCopy.size )
{
    ptr = new T[ size ];

    for ( int i = 0; i < size; ++i )
        ptr[ i ] = arrayToCopy.ptr[ i ];
}

template< typename T >
Array<T>::~Array()
{
    delete [] ptr; 
}

template< typename T >
int Array<T>::getSize() const
{
    return size;
}

template< typename T >
const Array<T> &Array<T>::operator=( const Array &right )
{
    if ( &right != this )
        {

            if ( size != right.size )
                {
                    delete [] ptr;
                    size = right.size; 
                    ptr = new T[ size ]; 
                }

            for ( int i = 0; i < size; ++i )
                ptr[ i ] = right.ptr[ i ]; 
        }

    return *this;
}

template< typename T >
bool Array<T>::operator==( const Array &right ) const
{
    if ( size != right.size )
        return false;

    for ( int i = 0; i < size; ++i )
        if ( ptr[ i ] != right.ptr[ i ] )
            return false; 

   return true; 
}

template< typename T >
T &Array<T>::operator[]( T subscript )
{

    if ( subscript < 0 || subscript >= size )
        throw out_of_range( "Subscript out of range" );

    return ptr[ subscript ];
}

template< typename T >
T Array<T>::operator[]( T subscript ) const
{

    if ( subscript < 0 || subscript >= size )
        throw out_of_range( "Subscript out of range" );

    return ptr[ subscript ]; 
}

// overloaded input operator for class Array;
// inputs values for entire Array

template< typename T >
istream &Array<T>::operator>>( istream &input, Array &a )
{
    for ( int i = 0; i < a.size; ++i )
        input >> a.ptr[ i ];

    return input; // enables cin >> x >> y;
} // end function 

// overloaded output operator for class Array
template< typename T> 
ostream &Array<T>::operator<<( ostream &output, const Array &a )
{
    int i;

    // output private ptr-based array 
    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;
        } // end for

    if ( i % 4 != 0 ) // end last line of output
        output << endl;
    return output; // enables cout << x << y;
} // end function operator<<

My main file:

#include <iostream>

#include "Array.h"

using namespace std;


int main()

{

    Array<int> integers1( 7 ); // seven-element Array

    Array<int> integers2; // 10-element Array by default



    // print integers1 size and contents

    cout << "Size of Array integers1 is "

         << integers1.getSize()

         << "\nArray after initialization:\n" << integers1;

}

Upvotes: 1

Views: 423

Answers (4)

mange
mange

Reputation: 3212

istream &Array<T>::operator>>( istream &input, Array &a ) shouldn't be in the Array<T> class.

With it like that it takes an implicit this argument, but you're explicitly passing the array you want in &a.

Change that line (and the corresponding operator<<, equivalently) to istream &operator>>(istream &input, Array<T> &a) and it should compile. This won't mess with other istream operators because of function overloading.

Upvotes: 1

Mooing Duck
Mooing Duck

Reputation: 66922

declaration:

template<typename T> istream &operator>>( istream &, Array<T> & );

definition:

istream &Array<T>::operator>>( istream &input, Array &a )
{

These should match. The declaration one is right, btw. This also applies to the ostream operator

Upvotes: 1

Dave S
Dave S

Reputation: 21113

In addition to the 'Template sources should be in headers' as pointed out by MSN, the lines for your overloaded stream operators in the source file are listed as:

template<typename T> istream &Array<T>::operator>>( istream &input, Array &a )
template<typename T>  ostream &Array<T>::operator<<( ostream &output, const Array &a ) 

However, the correct syntax for what you're attempting to accomplish is the one used in your header file:

template<typename T> istream &operator>>( istream &input, Array<T> &a )
template<typename T> ostream &operator<<( ostream &output, const Array<T> &a ) 

The declarations in your header file are generally refered to as the non-member stream operators. However, the ones in your source file are defining a member shift operator, which cannot be used for streaming, and must have only 1 argument.

If you change the declarations to match the header file, it should eliminate your compiler problem. That said, you will also need to place all of the contents of your source file into your header file or into a separate header which is included at the end of the first. If you do not, you will get linker errors when you try to create your executable.

Upvotes: 2

MSN
MSN

Reputation: 54604

You are putting the implementation of your template in a separate file without explicitly instantiating the types you are parameterizing.

In other words, you either need to explicitly instantiate the Array template for the types you are using or you need to make the template definition available with the template declaration. I.e., put all that stuff in the .cpp into the header.

Upvotes: 1

Related Questions