I'm pretty new to C++ and this site so there are bound to be errors. When I try to compile my code I get errors like error: missing template argument before 'b'. I've been searching the world for answers for hours and it has led me here.
My assignment is to implement a templated class Collection that stores a collection of
Objects using an array, along
with the current size of the collection.
#include <iostream>
#include "collection.h"
using namespace std; v
int main(int argc, char* argv[])
{
collection b; //<----error missing template argument before 'b'
return 0;
}
#ifndef COLLECTION_H
#define COLLECTION_H
#include <iostream>
template <typename obj>
class collection
{
public:
collection();
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
#include "collection.h"
template <typename obj>
collection<obj>::collection() :size(10)
{
col = new obj*[size];
}
template <typename obj>
bool collection<obj>::isEmpty() const
{
for(size_t k = 0; k < size; k++)
{
if(col[k] != NULL)
return false;
}
return true;
}
template <typename obj>
void collection<obj>::makeEmpty()
{
for(size_t k = 0; k < size; k++)
{
col[k] = NULL;
}
}
template <typename obj>
void collection<obj>::insert(obj val)
{
int temp = 0;
for(size_t s = 0; s < size; s++)
{
if(col[s] != NULL)
temp++;
}
if(temp >= size)
{
obj* temp = new obj*[size*2];
for(size_t c = 0; c < size; c++)
temp[c] = col[c];
delete col;
col = temp;
}
else
col[temp] = val;
}
template <typename obj>
void collection<obj>::remove(obj val)
{
for(size_t x = 0; x < size; x++)
{
if (col[x] == val)
{
for(size_t y = x; y < size-1; y++)
{
col[y] = col[y+1];
}
col[size-1] = NULL;
return;
}
}
}
template <typename obj>
bool collection<obj>::contains(obj val) const
{
for(size_t z = 0; z < size; z++)
{
if(col[z] == val)
return true;
}
return false;
}
You have to say what it's a collection of.
template <class A> class collection {}
requires that you use it as
collection<int> b;
or some appropriate type. That then makes a collection of ints. You haven't told it what you want a collection of.
First : Instantiate template by type. So if you have template <typename obj> class T {...}; you should use it like
void main {
T<int> t;
T<bool> t1; // .. etc
}
You can use a template with default value for the typename parameter defined in the class template declaration
template <typename obj = int> class T {/*...*/};
void main {
T<> t;
}
but anyway you should put empty angle brackets when use it without parameter.
Second: While declaring template, place it whole in the header file. Each definition of his methods should be in the file "*.h", don't ask me why, just don't split it to the header and "cpp" file.
Hope it helps.
Well, you're missing a template argument. You can't create a collection object, that's just a template.
You can only create e.g. a collection<int> or collection<std::string>.
You need to specify the type for template, like int or some other type:
collection<int> b;
There are a large number of errors in your code. First define your template in a header file:
In collection.h put the following:
#ifndef COLLECTION_H
#define COLLECTION_H
template <typename obj>
class collection
{
public:
collection() {}
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
Then in a .cpp file inside a main function do the following:
collection<int> b;
Instead of int you can use a different type but the main point is that YOU NEED A TYPE to instantiate a template.
Related
#ifndef SORTEDTYPE_H_INCLUDED
#define SORTEDTYPE_H_INCLUDED
const int MAX_ITEMS = 5;
template <class T>
class SortedType
{
public :
SortedType();
void MakeEmpty();
bool IsFull();
int LengthIs();
void InsertItem(T);
void DeleteItem(T);
void RetrieveItem(T&, bool&);
void ResetList();
void GetNextItem(T&);
private:
int length;
T info[MAX_ITEMS];
int currentPos;
};
#endif // SORTEDTYPE_H_INCLUDED
#include "sortedtype.h"
template <class T>
SortedType<T>::SortedType()
{
length = 0;
currentPos = - 1;
}
template <class T>
void SortedType<T>::MakeEmpty()
{
length = 0;
}
template <class T>
bool SortedType<T>::IsFull()
{
return (length == MAX_ITEMS);
}
template <class T>
int SortedType<T>::LengthIs()
{
return length;
}
template <class T>
void SortedType<T>::InsertItem(T item)
{
int location = 0;
for(int i= 0; i<length; i++)
{
if(info[location]<item)
location++;
else
break;
}
for(int i=length; i>location;i--)
{
info[i]=info[i-1];
}
info[location]= item;
length++;
}
template <class T>
void SortedType<T>::DeleteItem(T item)
{
int location=0;
for(int i=0; i<length; i++)
{
if(info[i] == item)
break;
location++;
}
for(int i=location; i<length; i++)
{
info[i] = info[i+1];
}
length--;
}
template <class T>
void SortedType<T>::RetrieveItem(T& item, bool &found)
{
int first=0, last=length-1, mid;
while(first<=last)
{
mid=(first+last)/2;
if(info[mid]== item)
{
found=true;
return;
}
if(info[mid]<item)
{
first=mid+1;
}
else
{
last=mid-1;
}
}
found=false;
}
template <class T>
void SortedType<T>::ResetList()
{
currentPos = - 1;
}
template <class T>
void SortedType<T>::GetNextItem(T& item)
{
currentPos++;
item = info [currentPos];
}
I am getting a redefinition error in the cpp file, can anyone please say, how to fix it?
I have tried all the possible things.
I am not getting what mistake have I done.
After building its just saying "error: redefinition of 'SortedType::SortedType()'"
and same thing for all the other functions.
What things can remove this error?
What changes can be done to fix it.
I have posted the code which I have written.
Functions that are defined within a header, have to be inline otherwise you get a redefinition error if they are used in multiple translation units.
If you define a member function within the body of the class then the member function is implicitly marked inline. If you define it outside of the class body, like in your example then you need to mark it inline explicitly, by adding the inline keyword in front of it.
I have a program that uses something I made called "SortableVector," with a parent called SimpleVector. The Simple Vector is fine, and so is most of SortableVector, but the problem is the sort function in SortableVector. It sorts numbers just fine, but I can't get it to sort strings. Here's what I originally had:
template <class T>
void SortableVector<T>::sort()
{
T temp = 0;
for(int i = 0; i < this->size(); i++)
{
for (int count = i+1; count < this->size(); count++)
{
if(this->operator[](0) == int)
{
if (this->operator[](count) < this->operator[](i))
{
temp = this->operator[](count);
this->operator[](count) = this->operator[](i);
this->operator[](i) = temp;
count = i+1;
}
}
}
}
}
Then I tried to use the sort(begin, end) function, but that didn't work either:
template <class T>
void SortableVector<T>::sort()
{
sort(this->operator[].begin(), this->operator[].end();
}
EDIT: To help people understand the problem, here's the whole file:
#ifndef SORTABLEVECTOR_H
#define SORTABLEVECTOR_H
using namespace std;
#include "SimpleVector.h"
#include <algorithm>
#include <fstream>
#include <string>
template <class T>
class SortableVector : public SimpleVector<T>
{
public:
SortableVector(int s) : SimpleVector<T>(s)
{}
SortableVector(SortableVector &);
SortableVector(SimpleVector<T> &obj):
SimpleVector<T>(obj)
{}
void sort();
};
template <class T>
SortableVector<T>::SortableVector(SortableVector &obj):SimpleVector<T>(obj)
{
}
template <class T>
void SortableVector<T>::sort()
{
std::sort(this->operator[].begin(), this->operator[].end());
T temp = 0;
for(int i = 0; i < this->size(); i++)
{
for (int count = i+1; count < this->size(); count++)
{
if(this->operator[](0) == int)
{
if (this->operator[](count) < this->operator[](i))
{
temp = this->operator[](count);
this->operator[](count) = this->operator[](i);
this->operator[](i) = temp;
count = i+1;
}
}
}
}
}
#endif
And this is SimpleVector:
// SimpleVector.h
#ifndef SIMPLEVECTOR_H
#define SIMPLEVECTOR_H
#include <iostream>
#include <cstdlib>
using namespace std;
template <class T>
class SimpleVector
{
private:
T *aptr;
int arraySize;
void subError(); // Handles subscripts out of range
public:
SimpleVector() // Default constructor
{ aptr = 0; arraySize = 0;}
SimpleVector(int); // Constructor
SimpleVector(const SimpleVector &); // Copy constructor
~SimpleVector(); // Destructor
int size() { return arraySize; }
T &operator[](int); // Overloaded [] operator
void print() const; // outputs the array elements
void push_back(T); // newly added function (implemention needed)
T pop_back(); // newly added function (implemention needed)
};
//****************************************************************
// Constructor for SimpleVector class *
// Sets the size of the array and allocates memory for it. *
//****************************************************************
template <class T>
SimpleVector<T>::SimpleVector(int s)
{
arraySize = s;
aptr = new T [s];
}
//*********************************************
// Copy Constructor for SimpleVector class *
//*********************************************
template <class T>
SimpleVector<T>::SimpleVector(const SimpleVector &obj)
{
arraySize = obj.arraySize;
aptr = new T [arraySize];
for(int count = 0; count < arraySize; count++)
*(aptr + count) = *(obj.aptr + count);
}
// *************************************
// Destructor for SimpleVector class *
// *************************************
template <class T>
SimpleVector<T>::~SimpleVector()
{
if (arraySize > 0)
delete [] aptr;
}
//************************************************************
// SubError function *
// Displays an error message and terminates the program when *
// a subscript is out of range. *
//************************************************************
template <class T>
void SimpleVector<T>::subError()
{
cout << "ERROR: Subscript out of range.\n";
exit(0);
}
//***********************************************************
// Overloaded [] operator *
// This function returns a reference to the element *
// in the array indexed by the subscript. *
//***********************************************************
template <class T>
T &SimpleVector<T>::operator[](int sub)
{
if (sub < 0 || sub >= arraySize)
subError();
return aptr[sub];
}
//********************************************************
// prints all the entries is the array. *
//********************************************************
template <class T>
void SimpleVector<T>::print( ) const
{
for (int k = 0; k < arraySize; k++ )
cout << aptr[k] << " ";
cout << endl;
}
//***************************************************************
// (1) push_back(T val) *
// The push_back function pushes its argument onto the back *
// Of the vector. *
//***************************************************************
template <class T>
void SimpleVector<T>::push_back(T val)
{
aptr[arraySize] = val;
arraySize++;
}
// *****************************************************
// (2) pop_back() *
// The pop_back function removes the last element *
// Of the vector. It also returns that value. *
// *****************************************************
template <class T>
T SimpleVector<T>::pop_back()
{
arraySize--;
T temp = aptr[arraySize];
return temp;
}
#endif
The SimpleVector was provided by the instructor.
You can do without the repeated this-> 99% of the time
You can just invoke operators, instead of invoking them as functions
You can just use std::sort from <algorithm>
Imagining some of the code you didn't show:
#include <vector>
#include <algorithm>
template <typename T>
struct SimpleVector {
std::vector<T> data;
virtual ~SimpleVector() {}
};
template <typename T>
struct SortableVector : public SimpleVector<T> {
void sort() {
std::sort(this->data.begin(), this->data.end());
}
};
#include <iostream>
int main()
{
SortableVector<std::string> sv;
sv.data = {"one","two","three","four"};
sv.sort();
for(auto& s : sv.data)
std::cout << s << ' ';
}
DISCLAIMER This seems a very non-c++ way to design classes. Algorithms and containers are traditionally separated, for good reason. The exception being that member functions sometimes perform operations in more optimal ways (e.g. std::set<>::find instead of std::find)
It should be std::sort(aptr, aptr + arraySize);. Also you should check arraySize > 0 before doing this, if you're intending to catch errors like that instead of having undefined behaviour.
begin and end aren't magic; they rely on the object either being an array (not a pointer), or the object implementing functions .begin() and .end() that return iterators.
You could even define those functions yourself, e.g. SimpleVector<T>::begin() { return aptr; } etc. , but maybe this is not a good idea as it bypasses your bounds-checking. You'd have to actually write an iterator class instead of returning a pointer, which is more trouble than you're ready for :)
NB. Everywhere you write this->operator[](foo), it would be clearer to write (*this)[foo]
I am getting an unresolved external compile error when compiling my template classes. I have separated the code into .h and .cpp files.
I read some posts and now I understand that this will not work due to linking issues as explained in this post.
include the full definition of the member function in the template's header file and not have a source file for the template,
define all the member functions in the template's source file as "inline", or
define the member functions in the template's source with the "export" keyword. Unfortunately this isn't supported by a lot of compilers.
However, none of these options will work since I have conversion functions between a number of these template functions (which results in a cross include compile issue).
How do I fix this issue?
EDIT: Include Code
StaticArray.h
template<typename T>
class Array;
template<typename T, unsigned int N>
class StaticArray
{
protected:
T* _data[N];
public:
StaticArray();
StaticArray(const StaticArray<T,N>& other);
~StaticArray();
void Release(unsigned int index);
void Release(T* data);
void ReleaseAll();
Array<T> ToArray();
bool operator == (const StaticArray<T,N>& other);
bool operator != (const StaticArray<T,N>& other);
T*& operator [] (unsigned int index) const;
StaticArray<T,N>& operator = (const StaticArray<T,N>& other);
};
StaticArray.cpp
#pragma region StaticArray::CoreMethods
template<typename T, unsigned int N>
StaticArray<T, N>::StaticArray()
{
for (unsigned int i = 0; i < N; i++)
{
this->_data[i] = null;
}
}
template<typename T, unsigned int N>
StaticArray<T, N>::StaticArray(const StaticArray<T,N>& other)
{
for (unsigned int i = 0; i < N; i++)
{
this->_data[i] = other._data[i];
}
}
template<typename T, unsigned int N>
StaticArray<T, N>::~StaticArray()
{
}
#pragma endregion
#pragma region StaticArray::Methods
template<typename T, unsigned int N>
void StaticArray<T,N>::Release(unsigned int index)
{
if (index < N)
{
delete this->_data[i];
this->_data[i] = null;
}
else
{
throw new Exception::IndexOutOfBoundsException("StaticArray accessed at index greater than N.");
}
}
template<typename T, unsigned int N>
void StaticArray<T,N>::Release(T* data)
{
if (data == null)
{
throw new Exception::InvalidArgumentException("StaticArray Release call argument must not be null.");
}
for (unsigned int i = 0; i < N; i++)
{
if (this->_data[i] == data)
{
this->Release(i);
return;
}
}
throw new Exception::InvalidArgumentException("StaticArray Release call argument was not in the array.");
}
template<typename T, unsigned int N>
void StaticArray<T,N>::ReleaseAll()
{
for (unsigned int i = 0; i < N; i++)
{
if (this->_data[i] != null)
{
delete this->_data[i];
this->_data[i] = null;
}
}
}
template<typename T, unsigned int N>
Array<T> StaticArray<T,N>::ToArray()
{
Array<T> ret(N);
for (unsigned int i = 0; i < N; i++)
{
ret[i] = this->_data[i];
}
return ret;
}
#pragma endregion
#pragma region StaticArray::OperatorOverloads
template<typename T, unsigned int N>
bool StaticArray<T,N>::operator == (const StaticArray<T,N>& other)
{
for (unsigned int i = 0; i < N; i++)
{
if (this->_data[i] != other._data[i])
{
return false;
}
}
return true;
}
template<typename T, unsigned int N>
bool StaticArray<T,N>::operator != (const StaticArray<T,N>& other)
{
return !((*this) == other);
}
template<typename T, unsigned int N>
T*& StaticArray<T, N>::operator[](unsigned int index) const
{
if (index < N)
{
return this->_data[index];
}
else
{
throw new Exception::IndexOutOfBoundsException("StaticArray accessed at index greater than N.");
}
}
template<typename T, unsigned int N>
StaticArray<T, N>& StaticArray<T, N>::operator = (const StaticArray<T,N>& other)
{
for (unsigned int i = 0; i < N; i++)
{
this->_data[i] = other._data[i];
}
return *this;
}
main.cpp
#include "StaticArray.h"
#include "Array.h"
int main(int argc, char** argv[])
{
StaticArray<int,5> sar;
sar[0] = new int(1);
sar[1] = new int(2);
sar[2] = new int(3);
sar[3] = new int(4);
sar[4] = new int(5);
return 0;
}
You don't have to have a definition of class Array to use class StaticArray except at the point you actually call ToArray. So it doesn't matter in which order the templates and their functions are declared, just as long as each one forward-declares the classes it uses.
Explicit template instantiation. Add this line to the bottom of StaticArray.cpp:
template class StaticArray<int,5>;
I see the forward declaration for class Array at the beginning of StaticArray.h. In your main.cpp try swapping the lines to
#include "Array.h"
#include "StaticArray.h"
from a quick glance it seems like the compiler hasnt seen Array when its building StaticArray and hence unresolved external?
I eventually managed to figure out the best way to make this functionality work in a structured manner.
You need to remove the conversions (such as StaticArray to Array) from the StaticArray class and instead have both StaticArray and Array included in another code file that contains utility functions (such as conversions).
The key here is to keep the includes working upwards. That is: utility.h (for example) includes Array.h and StaticArray.h instead of them including one another.
Then you are free to put all definition code into the StaticArray.h file with no cross-include side-effects (and thus fix the unresolved external).
How do I access the variables itemtype and total within the increment function? The code I have below gives me errors as follows
Counter2.h: In member function ‘int Counter::increment(T)’:
Counter2.h:28:31: error: ‘itemtype’ was not declared in this scope
Counter2.h:36:22: error: ‘itemtype’ was not declared in this scope
Counter2.h:36:39: error: ‘total’ was not declared in this scope
I must be able to use the command Counter<T> counter; where T can be any type, such as string and counter.increment()
#include<string>
//#include<cstdlib>
#include<vector>
using std::vector;
using std::string;
template<class T>
class Record{
public:
T itemtype;
int total;
};
template<class T>
class Counter{
vector< Record<T> > data;
public:
int increment(T item);
int count(T item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(T item){
bool check = false;
for(int i=0; i < data.size(itemtype); i++){
if(data[i].itemtype == item){
data[i].total++;
bool check = true;
break;
}
}
if(check == false){
data.push_back(itemtype = item, total = 1);
}
}
int main(){
Counter<string> counter;
counter.increment("orange");
counter.increment("orange");
return 0;
}
In line for(int i=0; i < data.size(itemtype); i++){
will be: for(int i=0; i < data.size(); i++){
And data.push_back(itemtype = item, total = 1); can be:
data.push_back({item, 1}); // by using initializer list ; C++11
or,
Record r;
r.itemtype = item;
r.total = 1;
data.push_back(r);
You can look at : http://www.cplusplus.com/reference/vector/vector/
to know about std::vector.
I'm not too sure I understand what you're after here, though for a start you're trying to access private members of class Record. You could make record a struct (public by default), or provide getters/setters or alternatively add:
friend class Counter;
to Record so that Counter can access its private members.
You can make Record a private structur inside Counter. That will not expose it implementation. You need to change also how you acces data. It is a vector of Record, not a Record. Something like:
template<class T>
class Counter
{
struct Record{ T itemtype; int total; };
vector< Record > data;
public:
int increment(const T& item);
int count(const T& item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(const T& item)
{
auto i=data.begin();
i= find(i,data.end(),[&item](const Record& r)
{return item==r.itemtype;});
if (i!=data.end())
return ++(i->total);
data.push_back({item, 1});
return 1;
}
If you dont like the lambda fun:
template<class T>
int Counter <T> :: increment(const T& item)
{
for(int i=0; i < data.size(); ++i)
if(data[i].itemtype == item)
return ++(data[i].total);
data.push_back({item, 1});
return 1;
}
But i think what you actually need is a multiset (if you dont care about the order). Something like this:
template<class T>
class Counter
{
std::multiset <T> data;
public:
int increment(T item);
int count(T item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(T item)
{
data.insert(item);
return data.count(item);
}
I'm in the early stage of trying to convert an array class containing operator overloading into a templatized class. At the moment I'm trying to add the template definition to the class and each function. This should be fairly simple however, whenever I run the program I get a scope error.
The compiler says `T' was not declared in this scope (I will comment the error on the line that it occurs). The error also re-occurs on the other function definitions. I'm using a program invovling a templatized class as a guide and it implements the functions in the exact manner that I am trying to(which is why I'm confused). What do I need to do to resolve this?
Thank you.
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <stdexcept>
using namespace std;
#ifndef ARRAY_H
#define ARRAY_H
template <typename T>
class Array
{
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);
}
int &operator[](int);
int operator[](int) const;
private:
int size;
int *ptr;
};
#endif
template<typename t>
Array<T>::Array(int arraySize) //ERROR: T was not declared in this scope***********
{
if(arraySize > 0)
size = arraySize;
else
throw invalid_argument("Array size myst be greater than 0");
ptr = new int[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 int[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::operator=(const Array &right)
{
if (&right != this)
{
if(size != right.size)
{
delete [] ptr;
size = right.size;
ptr = new int[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>
int &Array<T>::operator[](int subscript)
{
if(subscript < 0 || subscript >= size)
throw out_of_range("Subscript out of range");
return ptr[subscript];
}
template<typename t>
int Array<T>::operator[](int subscript) const
{
if(subscript < 0 || subscript >= size)
throw out_of_range("Subscript out of range");
return ptr[subscript];
}
int main()
{
//main is empty at the moment because I want to make sure that the class is functional
//before implementing the driver function.
system("pause");
}
Before each of your function definitions, you have written:
template<typename t>
You mean:
template<typename T>
That is, it should match the template parameter of your class, which is a capital T.