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);
}
Related
template <class T>
Row<T> Array2D<T>::operator[](int index) const
{
}
This code is not working, giving the error 'Declaration is incompatible with "Array2D::Row Array2D::operator[](int index) const" (declared at line 19". I'm using 2 templated classes, and I figure that that is the main issue but I'm not sure how it is fixed. Any help is appreciated, let me know if I need more details. Thanks.
Class Declaration:
#pragma once
#include "Array.h"
#include "Row.h"
template <class T>
class Array2D
{
template <class T> class Row;
public:
Array2D();
Array2D(int row, int col);
Array2D(const Array2D & copy);
~Array2D();
Array2D & operator =(const Array2D & rhs);
Row<T> operator[](int index) const;
int getRow() const;
void setRow(int rows);
int getColumns() const;
void setColumns(int columns);
T & Select(int row, int column);
private:
Array<T> m_array;
int m_row;
int m_col;
};
Row Class:
#pragma once
#include "Array2D.h"
template <class T>
class Row
{
template <class T> class Array2D;
public:
Row(Array2D<T> & array, int row);
T & operator[](int column);
private:
Array2D<T> & m_array2D;
int m_row;
};
template <class T>
Row<T>::Row(Array2D<T> & array, int row)
{
}
template <class T>
T & Row<T>::operator[](int column)
{
}
If you write
template <class T>
class Array2D
{
template <class T> class Row;
// ...
};
you say that Row is a template class defined inside Array2D.
The same when you write
template <class T>
class Row
{
template <class T> class Array2D;
// ...
};
You saying that Array2D is a template class defined inside Row.
I suppose you intention declare Raw and Array2D as independent classes, so something as
template <class T>
class Row;
template <class T>
class Array2D
{
// ...
};
and
template <class T>
class Array2D;
template <class T>
class Row
{
// ...
};
For example, I have a class template:
template <typename T>
class base {
public:
void set(T data) { data_=data; }
private:
T data_;
};
And for a certain type I would like to add a function, but also have functions from the template class.
template <>
class base<int>{
public:
void set(int data) { data_=data; }
int get(){ return data_;} //function specific to int
private:
int data_;
}
How to do that without copying all members from the template class?
With inheritance:
template <typename T> struct extra {};
template <> struct extra<int> {
public:
int get() const;
};
template <typename T>
class base : public extra<T> {
friend class extra<T>;
public:
void set(T data) { data_=data; }
private:
T data_ = 0;
};
int extra<int>::get() const{ return static_cast<const base<int>*>(this)->data_;}
Demo
You can do this by using enable_if from type_traits to enable the get function only when the template parameter is int. One example is shown below.
#include <type_traits>
template <typename T>
class base {
public:
template <typename X=T,
std::enable_if_t< std::is_same<X,typename T>::value
&& std::is_same<X,int>::value, bool> = false>
int get() { return data_; }
void set(T data) { data_=data; }
private:
T data_;
};
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
I'm trying to create a class, which will contain two pairs of template functions: one for char and one for wchar_t. I wrote the following code, but it couldn't be built because linker cannot find realizations of functions. I think the problem is that linker thinks the functions in the class are not the instantiations of template ones.
How can I define the functions needed?
template<typename T>
int func1(const T* szTarget)
{
...
}
template<typename T>
T* func2(const T* szTarget)
{
...
}
class MyClass
{
public:
int func1(const char* szTarget);
int func1(const wchar_t* szTarget);
char* func2(const char* szTarget);
wchar_t* func2(const wchar_t* szTarget);
};
Actually you're defining two template function outside the scope of your class, they are not related with your class by any way.
So why not just :
class MyClass
{
public:
template<typename T>
int func1(const T* szTarget)
{
/* ... */
}
template<typename T>
T* func2(const T* szTarget)
{
/* ... */
}
};
By the way, you should experiment with scopes and naming to understand it a bit: http://ideone.com/65Mef5
What about
class MyClass {
public:
template<typename T>
int func1(T* szTarget) {
// provide appropriate implementation
}
template<typename T>
char* func2(T* szTarget) {
// provide appropriate implementation
}
};
The compiler is right.
You have to declare the template functions as members of the class. Which means they need to be declared inside the class declaration.
class MyClass
{
public:
template<typename T>
int func1(const T* szTarget)
{
...
}
template<typename T>
T* func2(const T* szTarget)
{
...
}
template <> int func1(const char* szTarget) { } //specialization
template <> int func1(const wchar_t* szTarget) { } //specialization
template <> char* func2(const char* szTarget) { } //specialization
template <> wchar_t*func2(const wchar_t* szTarget) { } //specialization
};
You haven't defined any templated methods in your class. One way of doing it is as follows:
class MyClass
{
public:
template <typename T> int func1(const T* szTarget);
template <typename T> T* func2(const T* szTarget);
};
template<typename T>
int MyClass::func1<T>(const T* szTarget)
{
...
}
template<typename T>
T* MyClass::func2<T>(const T* szTarget)
{
...
}
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.