Reputation: 204
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
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
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
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
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