C++ Abstract Template Class - c++

I am trying to utilize an abstract template base class.
The compiler is giving errors in RowArray.cpp that the members rowPntr, and rowSize are "not declared in this scope." Both are protected members from the abstract class AbsRow. I am guessing that this design is not possible because it utilizes virtual functions, which are dynamical bound at run time, but at the same time uses a template which is bound at compile time. Perhaps mixing the two is the issue? What I would like to know is if my design is possible, and why am I getting these compiler errors? I did also forget to mention that when creating a RowArray object RowArray<int> obj(5); I get link error 2019 in visual studio and in Qt creator it tells me undefined reverence to RowArray constructor and destructor.
Abstract class AbsRow.h
template <typename T>
class AbsRow
{
public:
virtual int getSize()const = 0;
virtual T getValue(int index)const = 0;
protected:
T *rowPntr;
int rowSize;
};
Derived Class RowArray.h
#include "absrow.h"
template <class T>
class RowArray : public AbsRow<T>
{
public:
RowArray(const int rows);
virtual ~RowArray();
virtual T getValue(int index) const override;
virtual int getSize() const override;
void setValue(int row, int value);
};
RowArray.cpp
#include "rowarray.h"
#include <cstdlib>
template <class T>
RowArray<T>::RowArray(const int rows)
{
rowSize = rows;
rowPntr = new int[rows];
for(int index = 0; index < rows; index++)
{
rowPntr[index] = (rand() % 90) + 10;
}
}
template <class T>
RowArray<T>::~RowArray()
{
delete [] rowPntr;
}
template <class T>
void RowArray<T>::setValue(int row, int value)
{
rowPntr[row] = value;
}
template <class T>
int RowArray<T>::getSize() const
{
return rowSize;
}
template <class T>
T RowArray<T>::getValue(int index) const
{
return rowPntr[index];
}
Main
#include "rowarray.h"
int main()
{
RowArray<int> row(7);
}

You can address that basically in two ways... Taking a shortened example of your RowArray.cpp ... (I also fixed a problem in your new expression)
template <class T>
RowArray<T>::RowArray(const int rows)
{
AbsRow<T>::rowSize = rows
// or
//this->rowSize = rows;
AbsRow<T>::rowPntr = new T[rows]; ///Corrected 'int' to 'T' because rowPntr is of type 'T*' in your AbsRow class
// or
//this->rowPntr = new T[rows];
for(int index = 0; index < rows; index++)
{
AbsRow<T>::rowPntr[index] = (rand() % 90) + 10;
// or
//this->rowPntr[index] = (rand() % 90) + 10;
}
}

I think error comes from the fact that you are putting template code (the derived class is still a template) into a CPP file. The compiler has to see the entire template implementation, which usually means putting the whole thing in a header file.
Another problem is that the derived class constructor assumes that rowPntr of of type int* but it is really T*.

The root cause for the problem here is, it is expected to have function definitions for template class in .h file itself. If you are not doing that compiler won't be able to link the definition from the .cpp file. There are few hacks to overcome this. One is to have an explicit template initialization in the .cpp file.
At the of RowArray.cpp add
template class AbsRow<int>;
template class RowArray<int>;

Related

Can derived class member functions return different types than the base class?

I am running into a design issue with my code and I am not sure where to go. I am attempting to write a basic I/O class to write vectors of data into a text file for convenience in my research. In practice, I would like to not worry about the datatype in the array that I am writing to file and use the same interface regardless of if it is an array of ints, doubles, etc.
My basic idea was to create an AbstractColumn class, with a templated derived class to handle columns of different data. My I/O class could then contain an array of pointers to objects of this Abstract Class, and I can can add to this array as needed. See my header file below for the implementation of this.
#ifndef BASICIO_H
#define BASICIO_H
#include <vector>
#include <cstring>
#include <string>
#include <stdlib.h>
struct AbstractColumn{
virtual ~AbstractColumn() = 0;
template <class T> T* get_data(); // Issue comes in here, I think
int nrows=0;
};
template <class T>
class Column : public AbstractColumn {
public:
Column(std::vector<T>& v);
~Column();
T* get_data() {return data;}
T* data;
int nrows;
};
template <class T>
Column<T>::Column(std::vector<T>& v){
nrows = v.size();
data = static_cast<T*>(malloc(sizeof(T)*v.size())); //malloc returns void* so we need the static cast
std::memcpy(data, v.data(), v.size());
}
template <class T>
Column<T>::~Column() {}
class BasicIO {
public:
BasicIO(std::string outname) : fname(outname), ncols(0) {}
~BasicIO();
template <class T>
void attach(std::vector<T>& v, std::string name="");
void write();
inline int get_ncols() {return ncols;}
inline std::string filename() {return fname;}
private:
std::vector<AbstractColumn*> columns;
std::vector<std::string> column_names;
std::string fname;
int ncols;
};
template <class T>
void BasicIO::attach(std::vector<T>& v, std::string name){
Column<T>* col = new Column(v);
columns.push_back(col);
column_names.push_back(name);
}
#endif
My issue is coming in in trying to write the write() method that actually dumps this data to a file.
void BasicIO::write(){
// other formatting code here
for(int i = 0; i<columns.at(0)->nrows; i++){
for(int j = 0; j<ncols; j++){
outfile<<std::scientific<<std::left<<std::setw(col_width)<<(columns.at(j)->get_data())[i]<<" ";
} //^ this is causing an error
outfile<<std::endl;
}
outfile.close();
}
When I try to compile, I get the an error saying note: template argument deduction/substitution failed and couldn't deduce template parameter 'T'. Now, I think I understand what the issue is. When the compiler reaches this point, all it doesn't know what type of data is going to be returned by my get_data() function, since in the base class the return type is the template T. However, I don't see a way around this and I am very stuck. I have done a bit of reading and it seems like type erasure might be the way to go, but I also think I might be missing something simpler.
My Question
All of the above context aside, my concrete question is as follows: What is the best way to have an array which holds objects (in this case columns) of generic types, specifically for the application described above? I am happy to offer any other details as needed, I just felt that my code snippets were already quite long. Thank you for reading.

How does C++ know which attribute to use

I have the incomplete class below (but the necessary is there to understand my concern).
The following method is copying the content of a given bag (called sac in my code)
template <class T, int capInitial>
Sac<T,capInitial>& Sac<T,capInitial>::
operator+=(Sac &b) {
for(int i=0; i<b.getTaille(); i++){
*this += b.sac[i]; //LINE i DON'T UNDERSTAND
}
return *this;
}
Since the class Below has 2 attributes and a pointer to an array. In the line mentioned above what mechanism enable to take all elements in the given argument and just add it to the array of the class via *this+=b.sac[i], i would have done it in the following way
for(int i=0; i<b.getTaille(); i++){
sac[taille++]= b.sac[i];
Or perhaps there is something i don't quite understand? here is the incomplete class
template <class T, int capInitial>
class IterateurSac;
template <class T, int capInitial=64>
class Sac {
private:
T* sac;
int taille;
int capacite;
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution;
void augmenterCapacite(int cap);
void copier(const Sac &b);
public:
Sac() : taille(0), capacite(capInitial), generator(7437843) {
sac= new T[capacite];
}
template <class T, int capInitial>
Sac<T,capInitial>& Sac<T,capInitial>::
operator+=(const T &element) {
if (taille==capacite)
augmenterCapacite(2*capacite);
sac[taille++]= element;
return *this;
}
}
In C++, you can create your own behaviour for operators. Your class would need to overload operator+= to make this work, and that function would name the member variable to modify.
Indeed, we can see from your first code snippet that the class is already overloading operator+= to take an argument of type Sac<T,capInitial>&; it must have another one taking an argument of type T (or compatible).
What's not clear is why the class definition you later show us does not include a declaration for either of those functions.

how to define a static variable of generic type

I have written a class as below:
template <class T>
/* Abstract class for stack n queue */
class StacknQueue
{
public:
StacknQueue(int = 10);
virtual int insert(const T&) = 0;
virtual int remove(T&) = 0;
virtual void display() = 0;
int isEmpty() const {return top == -1 || front == -1 || front > top ;}
int isFull() const { return top == size - 1 ;}
//virtual int isQEmpty const() = 0;
//virtual int isQFull const() = 0;
void initialize();
static int flag;
static int size;
//int rear;
static int front;
static int top;
static T *stknqPtr ;
};
when I try to define the variable stknqPtr outside class as below:
template <class T>
T StacknQueue<T> :: stknqPtr = new T[size];
its giving me error:
error C2040: 'stknqPtr' : 'float' differs in levels of indirection from 'float *'
I am new to c++ can anyone suggest me how to proceed.
Thanks in advance
Your definition has the wrong type. It fails to define a pointer. It should be:
template <class T>
T* StacknQueue<T>::stknqPtr = ...;
You need to make it the right type - It's T* in the class, but T in the definition.
But - your class design suggests that all it's members should not be static - otherwise every instance is going to share the same backing-data - not what you usually want for a stack or queue. And for non-static members you dont need the annoying explicit instantiation - so everything becomes easy.

Explicit template specialization

I hate to ask such a general question, but the following code is a exercise in explicit template specialization. I keep getting the error:
c:\users\***\documents\visual studio 2010\projects\template array\template array\array.h(49): error C2910: 'Array::{ctor}' : cannot be explicitly specialized
#ifndef ARRAY_H
#define ARRAY_H
template <typename t>`
class Array
{
public:
Array(int);
int getSize()
{
return size;
}
void setSize(int s)
{
size = s;
}
void setArray(int place, t value)
{
myArray[place] = value;
}
t getArray(int place)
{
return myArray[place];
}
private:
int size;
t *myArray;
};
template<typename t>
Array<t>::Array(int s=10)
{
setSize(s);
myArray = new t[getSize()];
}
template<>
class Array<float>
{
public:
Array();
};
template<>
Array<float>::Array()
{
cout<<"Error";
}
#endif
Thanks
The implementation of the specialization's constructor isn't a template! That is, you just want to write:
Array<float>::Array()
{
std::cout << "Error";
}
Actually, it seems that you want to restrict the use of your 'Array' class template to not be used with 'float' in which case you might want to only declare but not define you specialization to turn the run-time error into a compile-time error:
template <> class Array<float>;
Of course, there are many variations how you can prevent instantiation of classes. Creating a run-time error seems to be the worst option, however.

How to make this specialized function work

Here's the deal. I've looked on this forum and I didn't find the information I'm searching for or I'm probably not able to repeat it for my problem. I have a class Table which is generic and I have a class named MyString.
template <typename typeGen, int DIM>
class Table {
public:
TableauGenerique() : index_(0) { //On initialise courant à 0
}
void add(typeGen type);
private:
typeGen tableGen_[DIM];
int index_;
};
My problem is with the add function.
I sometimes have to do this in the main.cpp: (which works well)
Table <float,6> tabFloat;
tabFloat.add(1.6564);
and at one point, I need to do this which doesn't work because I need to specialize the add function to create an object of MyString, to pass it the string and then store the object in the array (tableGen) :
TableauGenerique <MyString,4> tabString;
So I tried this (after the class), without success.
template <typename typeGen, int DIM>
void Table<typeGen,DIM>::add(typeGen type){ //Which is the generic one for float or ints
if(index_ < DIM) {
tableGen_[courant_] = type;
index_++;
}
}
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type) { //(line 75) Which is the specific or specialized function for myString
MyString str(type);
if(index_ < DIM) {
tableGen_[courant_] = str;
index_++;
}
}
So, How can I make this work because it doesn't compile at all, saying: line75 : error: expected initializer before '<' token and in the main it says not matching function to call Table::add(const char[6]),
I hope everything is clear enough. Let me know if somethings is unclear.
Thank you very much for your help !
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type)
You're trying to specialize add() when in fact it is not a function template to begin with. How do you expect it to work?
You probably meant: (specialization of the class)
template <int DIM>
void Table<string,DIM>::add(string type)
But then this is allowed only if you specialize the class itself. Without specializing the class, the above code would give compilation error!
EDIT:
You can read these online tutorials:
Introduction to C++ Templates
14.5 — Class template specialization
Template Specialization and Partial Template Specialization
Explicit specialization (C++ only)
If you can control the code of the MyString class, you can provide constructors that act as implicit conversions from float to MyString. An example:
#include <string>
#include <sstream>
#include <iostream>
class MyString {
public:
MyString(float number) {
std::stringstream buffer;
buffer << number;
value = buffer.str();
}
void print() {
std::cout << value << std::endl;
}
private:
std::string value;
};
template <class T>
class Foo {
public:
void DoStuff(T item) {
item.print();
}
};
int main() {
Foo<MyString> foo;
foo.DoStuff(1.342); // implicitly converts float to MyString
return 0;
}
This way, you do not need any specialization of the add method. However, implicit conversions are tricky, and you have be careful not to invoke them accidentally, and they may create ambiguities.
EDIT: Upon a second thought, my suggestion below is basically equivalent to
Table<MyString,4> tabString;
tabString.add(MyString("whatever"));
and therefore excessive and/or does not solve the problem. Feel free to ignore :)
I would extend the class Table with a generic method to add something from which you can construct an object of the desired type:
template <typename typeGen, int DIM>
class Table {
public:
Table() : index_(0) {}
void add(typeGen type);
// The additional method
template<typename T> void add(const T& src);
private:
typeGen tableGen_[DIM];
int index_;
};
template<typename typeGen, int DIM>
template<typename T>
void Table<typeGen,DIM>::add(const T& src) {
if(index_ < DIM) {
tableGen_[courant_] = typeGen(src);
index_++;
}
}
Note construction of a temporary typeGen object before the assignment.
Assuming that MyString object can be constructed from a string literal, i.e. from const char*, you can then use it as following:
Table<MyString,4> tabString;
tabString.add("whatever");
or if the above assumption is wrong, the following should probably work (because you constructed a MyString instance from a string instance):
tabString.add(string("whatever"));