I had implemented array class which overloads some operators to perform some mathematical operations. Then, I reimplemented this program with templates so that I can fill the array with any kind of datatypes. However, I can beat the linking issue with the statement:
template class array<double>;
But this statement force my program to get only double value to my array. Otherwise, undefined reference for the functions happens.
My whole code is below:
array.h
#ifndef __PARANTHESIS_H
#define __PARANTHESIS_H
#include <iostream>
#include <initializer_list>
#include <iomanip>
template <typename T>
class array
{
private:
template <typename U>
friend std::istream &operator>>( std::istream &, array<U> &);
template <typename V>
friend std::ostream &operator<<( std::ostream &, const array<V> & );
size_t row;
size_t col;
T **ptr;
public:
explicit array ( size_t = 1 , size_t = 6 );
array( const array<T> & );
array( std::initializer_list <std::initializer_list<T>> list );
~array();
size_t getRow() const;
size_t getColumn() const;
T& operator()( size_t , size_t );
bool operator==(const array<T>& ) const;
bool operator!=(const array<T>&) const;
};
/* compiler doesn't generate linker issue if friend functions are defined here */
template <typename T>
std::ostream &operator<<(std::ostream &output, const array<T> &arr) {
for (size_t i = 0; i < arr.row; i++)
{
for (size_t j = 0; j < arr.col; j++)
{
std::cout << std::setw(2 * arr.col + 1) << arr.ptr[i][j];
}
output << std::endl;
}
return output;
}
template <typename T>
std::istream &operator>>( std::istream &input, array<T> &a ) {
//output private ptr-based array
for (size_t i = 0; i < a.row; i++)
{
for (size_t j = 0; j < a.col; j++)
{
input >> a.ptr[i][j];
}
}
return input;
}
#endif
array.cpp
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include "array.h"
template <typename T>
array<T>::array ( size_t row, size_t col )
: row( row > 0 ? row : throw std::invalid_argument( "Row must be > 0" ) ),
col( col > 0 ? col : throw std::invalid_argument( "Column must be > 0" ) )
{
ptr = new T*[row];
for (size_t i = 0; i < row; i++)
{
ptr[i] = new T[col];
for (size_t j = 0; j < col; j++)
{
ptr[i][j] = 0.0;
}
}
}
template <typename T>
array<T>::array( const array<T> &arr )
: row( arr.row ),
col( arr.col),
ptr ( new T* [row] )
{
for (size_t i = 0; i < row; i++)
{
ptr[i] = new T[col];
for (size_t j = 0; j < col; j++)
{
ptr[i][j] = arr.ptr[i][j];
}
}
}
template <typename T>
array<T>::array(typename std::initializer_list<std::initializer_list<T>> list)
:row(list.size())
{
ptr = new T*[row];
typename std::initializer_list < std::initializer_list <T>> ::iterator roww;
typename std::initializer_list<T>::iterator coll;
size_t i, j;
for (roww = list.begin(), i = 0; roww != list.end(); ++i, roww++)
{
col = roww->size();
ptr[i] = new T[col];
for (coll = roww->begin(), j = 0; coll < roww->end(); ++j, coll++)
{
ptr[i][j] = *coll;
}
}
}
template <typename T>
array<T>::~array() {
for (size_t i = 0; i < row; i++)
{
delete []ptr[i];
}
delete []ptr;
}
template <typename T>
bool array<T>::operator==(const array &arr) const {
if((arr.col != col) || (arr.row != row)) // check the dims.
return false;
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
if (ptr[i][j] != arr.ptr[i][j])
{
return false;
}
}
}
return true;
}
template <typename T>
bool array<T>::operator!=(const array& right) const{
return !(*this == right);
}
template <typename T>
size_t array<T>::getSize() const {
return row * col;
}
template <typename T>
size_t array<T>::getRow() const {
return row;
}
template <typename T>
size_t array<T>::getColumn() const {
return col;
}
template class array<double>; // linking issue arises if commented
main.cpp
#include <iostream>
#include <stdexcept>
#include "array.h"
int main(int argc, char const *argv[])
{
//array<int> arr(2,3) -> yields error, to handle this, use template class array<int>;
array<double> arr(2,3);
std::cin >> arr;
array<double> arr2{{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}};
std::cout.precision(2);
std::cout << arr2;
array<double> arr3(2);
std::cout << "Enter 12 numbers:";
std::cin >> arr3;
std::cout << arr3;
array<double> arr4 = arr3;
std::cout << arr4;
std::cout << "arr4 == arr3 = " << (arr4 == arr3) << std::endl;
std::cout << "arr4 != arr3 = " << (arr4 != arr3) << std::endl;
std::cout << "arr2 != arr = " << (arr2 != arr) << std::endl;
std::cout << "arr2 == arr = " << (arr2 == arr) << std::endl;
return 0;
}
How to solve this issue? I mean it doesn't mean anything if I implement this program with templates but I cannot input various types. In this case, I can only input integer variable, and it bothers me. Thx in advance for your helps.