I am using Microsoft Visual Studios and I have create a generic class List_Array. There is no problem with the default constructor, but the other two (overloaded) constructors are generating the error.
//List_Array.h
template<typename T>
class List_Array {
private:
int size; ...
T* data;
public:
List_Array<T>::List_Array();
List_Array<T>::List_Array(int);
List_Array<T>::List_Array(const T&, int);
...
};
template<typename T>
List_Array<T>::List_Array() { }
template<typename T>
List_Array<T>::List_Array(int s) {
this->size = s
this->data = new T[s];
}
template<typename T>
List_Array<T>::List_Array(const T& init, int s){
this->size = s;
this->data = new T[s];
for (int i = 0; i < s; i++){
this->data[i] = init;
}
}
I get a C2244 'List_Array::List_Array': unable to match function definition to an existing declaration
Any help is much appreciated!
The problem has nothing to do with template or overloading. You just don't need List_Array<T>:: part for the member function declaration inside class definition. i.e.
template<typename T>
class List_Array {
private:
int size; ...
T* data;
public:
List_Array();
List_Array(int);
List_Array(const T&, int);
...
};
LIVE
Related
Here I've implemented a class called Vector and tried to overload = operator with a parameter initialized_list.
#include<iostream>
using namespace std;
template<class T>
class Vector
{
private:
T* arr;
int _size;
int capacity;
public:
Vector();
~Vector();
Vector<T>& operator = (const initializer_list<T>& l);
};
template<class T>
Vector<T>& Vector<T>::operator = (const initializer_list<T>& l)
{
_size=capacity=l.size();
arr=new T[l.size()];
return *this;
}
template<class T>
Vector<T>::Vector()
{
_size=0;
capacity=0;
}
template<class T>
Vector<T>::~Vector()
{
delete[] arr;
}
In this implementation if I run with the code below it works fine.
int main()
{
Vector<int>v;
v={1,2,3};
}
But if I want to run with this code below it shows error: could not convert '{1, 2, 3}' from '<brace-enclosed initializer list>' to 'Vector<int>'
int main()
{
Vector<int>v={1,2,3};
}
How can I fix this problem to make it work as the code above?
I try to implement a template with an explicit template specification. The template and its implementation is shown bellow:
template <typename T>
class MyClass {
private:
T data;
size_t size;
public:
MyClass();
~MyClass();
uint32_t getSize();
T getData();
void setData(T value);
};
template <class T>
MyClass<T>::MyClass()
{
size = sizeof(T);
}
template <>
MyClass<std::string>::MyClass()
{
size = 0;
}
/* and so on */
Now I have an issue when my explicit declaration contains also a class template. Let say, i would create an explicit template specialization of a vector (containing any primitive type like int, char, float,...) and store the element site in the size variable.
template <??>
MyClass<std::vector<?>>::MyClass()
{
size = sizeof(?);
}
How could I do this?
You should specialize class, not methods:
#include <string>
#include <vector>
template <typename T>
class MyClass {
private:
T data;
size_t size;
public:
MyClass();
~MyClass();
uint32_t getSize();
T getData();
void setData(T value);
};
template <class T>
MyClass<T>::MyClass()
{
size = sizeof(T);
}
template <>
MyClass<std::string>::MyClass()
{
size = 0;
}
template<class T>
class MyClass<std::vector<T>>
{
MyClass();
T data;
size_t size;
};
template<class T>
MyClass<std::vector<T>>::MyClass()
{
size = sizeof(T);
}
I wrote things like that:
template <class T>
MyStack<T>::MyStack()
{
STACK_SIZE=20;
STACK_CURRENT=0;
data=new T[STACK_SIZE];
}
template <class T>
MyStack<T>::MyStack(int thesize)
{
STACK_SIZE=thesize;
STACK_CURRENT=0;
data=new T[STACK_SIZE];
}
template <class T>
MyStack<T>::MyStack(const MyStack& obj)
{
STACK_SIZE=obj.STACK_SIZE;
STACK_CURRENT=obj.STACK_CURRENT;
data=new T[STACK_SIZE];
for(int i=0; i<STACK_CURRENT; i++)
{
data[i]=obj.data[i];
}
}
template <class T>
MyStack<T>::~MyStack()
{
//do nothing
}
//--------------------Get Error below this line-------------------------
template <class T> MyStack& MyStack<T>::operator=(const MyStack& obj)
//--------------------Get Error in this line---------------------------
{
STACK_SIZE=obj.STACK_SIZE;
STACK_CURRENT=obj.STACK_CURRENT;
data=new T*[STACK_SIZE];
for(int i=0; i<STACK_CURRENT; i++)
{
data[i]=obj.data[i];
}
return *this;
}
template <class T>bool MyStack<T>::empty()
{
if(STACK_CURRENT==0) return true;
return false;
}
template <class T> T& MyStack<T>::top()
{
return data[STACK_CURRENT-1];
}
template <class T> void MyStack<T>::push(T& obj)
{
if(STACK_CURRENT>=STACK_SIZE-3)
{
T* tempdata=new T[STACK_SIZE*2];
for(int i=0; i<STACK_CURRENT; i++)
{
tempdata[i]=data[i];
}
delete[] data;
data=new T[STACK_SIZE*2];
for(int i=0; i<STACK_CURRENT; i++)
{
data[i]=tempdata[i];
}
STACK_SIZE+=STACK_SIZE;
}
data[STACK_CURRENT]=obj;
STACK_CURRENT++;
}
template <class T> void MyStack<T>::pop()
{
STACK_CURRENT--;
}
template <class T> int MyStack<T>::size()
{
return STACK_CURRENT;
}
My Header has declaration
template<class T> class MyStack
{
public:
MyStack();
MyStack(int);
MyStack(const MyStack&);
~MyStack();
MyStack& operator=(const MyStack&);
bool empty();
T& top();
void push(T&);
void pop();
int size();
private:
int STACK_SIZE;
int STACK_CURRENT;
T* data;
};
But I can't pass compiling, why? Thanks!
Out-class member function definitions should also mention type argument:
template <class T>
MyStack<T>& MyStack<T>::operator=(const MyStack<T>& obj)
// ^^^ you forgot this ^^^ this too!
Just see these demos:
http://www.ideone.com/BEMYn (error)
http://www.ideone.com/f6Qzu (fixed)
Templated classes must be fully instantiated at compilation time, not linking time. So,
Either you define all functions in the header,
Either you use that class only in the compilation unit that defines the functions (so: MyStack.cpp).
Your erroneous line should be
template <class T> MyStack<T>& MyStack<T>::operator=(const MyStack& obj)
instead of
template <class T> MyStack& MyStack<T>::operator=(const MyStack& obj)
I am writing a generalized container using a class template, with a restriction (policy) that the items stored in the container should derive from a specific base class.
Here is the definition of the class template
// GenericContainer.hpp
// --------------------------------------
class ContainerItem
{
protected:
virtual ContainerItem& getInvalid() = 0;
public:
virtual ~ContainerItem();
bool isValid() const;
};
template<typename D, typename B>
class IsDerivedFrom
{
static void Constraints(D* p)
{
B* pb = p; // this line only works if 'D' inherits 'B'
pb = p; // suppress warnings about unused variables
}
protected:
void IsDerivedFrom2() { void(*p)(D*) = Constraints; }
};
// Force it to fail in the case where B is void
template<typename D>
class IsDerivedFrom<D, void>
{
void IsDerivedFrom2() { char* p = (int*)0; /* error */ }
};
template <class T>
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T& elementAt(const unsigned int pos) const;
};
template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
m_elems.push_back(elem);
}
template <class T>
unsigned int GenericContainer<T>::size() const
{
return m_elems.size();
}
template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
// Class to be contained (PURPOSELY, does not derive from ContainerItem)
// Data.hpp
//----------------------------------------------------------------
class Data
{ /* implem details */};
// Container for Data items
// Dataset.h
// ----------------------------------------------------------------------------
#include "GenericContainer.hpp"
#include "Data.hpp"
class Dataset: public GenericContainer<Data>
{
public:
Data& getInvalid();
};
// C++ source
// -----------------------------------------------------------
#include "Dataset.hpp"
Dataset ds;
Can anyone explain why the code above compiles?.
[Edit]
The code above should NOT compile for two reasons:
The class 'Data' does NOT derive from ContainerItem, and yet it can be stored in GenericContainer (as illustrated by the class Dataset). Incidentally, this issue has now been resolved thanks to the answer given by Omifarious and jdv
The class 'Data' does NOT implement the pure virtual method declared in the ABC ContainerItem - using the fixes recommended in the answers below, the first issue (enforcement of policy) is resolved, however the compiler fails to notice that Data does not implement the getInvalid() method of the ContainerItem 'interface'. Why is the compiler missing this glaring mistake?
BTW, compiler and OS details are:
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Change IsDerivedFrom2 to IsDerivedFrom and it fails to compile in just the expected manner.
The problem is that a method from a template class is never instantiated if it isn't called. Changing the name makes it a constructor, so it then ends up being called by the constructors of classes derived from IsDerivedFrom. It will still compile to empty code. The compiler will optimize it away the dead assignment.
I would recommend you not write template code like this yourself if you can manage to use Boost, particularly is_base_of from the Boost type traits library.
In particular, your GenericContainer template can be more simply and easily implemented this way using Boost:
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
template <class T>
class GenericContainer
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T& elementAt(const unsigned int pos) const;
GenericContainer() {
BOOST_STATIC_ASSERT( (::boost::is_base_of<ContainerItem, T>::value) );
}
};
template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
m_elems.push_back(elem);
}
template <class T>
unsigned int GenericContainer<T>::size() const
{
return m_elems.size();
}
template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
The Constraints function is not generated because IsDerivedFrom2 is never referenced. This is required behavior for C++. Maybe it helps to call it from the constructor. Otherwise, check the boost library for functionality like this.
I wrote this something-like-stack data structure:
template<class T>
class Stos {
class Element {
public:
T n;
Element* prev;
Element(const T& k = 0): n(k), prev(0) {}
};
Element* member;
Stos(Stos&);
public:
Stos(const T&);
~Stos();
unsigned int count;
T get();
Element* push(const T&);
T pop();
void mod(const T&);
};
And implementation (same file):
template<class T>
Stos<T>::Stos(const T& n = 0): count(1) {
member = new Element(n);
}
template<class T>
T Stos<T>::get() {
return member->n;
}
template<class T>
Stos<T>::Element* Stos<T>::push(const T& n = 0) {
Element* point = member;
member = new Element;
member->prev = point;
if(n != 0) member->n = n;
++count;
return member;
}
template<class T>
T Stos<T>::pop() {
Element* point = member;
T n = point->n;
member = point->prev;
--count;
delete point;
return n;
}
template<class T>
void Stos<T>::mod(const T& n) {
member->n = n;
}
template<class T>
Stos<T>::~Stos() {
while(member) pop();
}
And when I try to compile it with g++, I get this error about the first line of definition of Stos::Element* Stos::push(): expected constructor, destructor, or type conversion before ‘*’ token. It is my first try to write something with templates. This stack code did work without templates, when I'd edited it, then I got the error, everything worked just fine before with "int" everywhere instead of "T".
And I can't find out why it doesn't compile. Can't I use pointer to class::member?
You need to prefix the name Element with typename
typename Stos<T>::Element* Stos<T>::push(const T& n = 0)
Here's a link to a full explanation of why this is necessary
http://pages.cs.wisc.edu/~driscoll/typename.html
You should also consider using
const T &n = T()
instead of
const T &n = 0
Since not all possible T may be able to be initialized from 0!