Template class copy constructor - c++

I want to write copy constructor for a template class. I have this class:
template<int C>
class Word {
array<int, C> bitCells; //init with zeros
int size;
public:
//constructor fill with zeros
Word<C>() {
//bitCells = new array<int,C>;
for (int i = 0; i < C; i++) {
bitCells[i] = 0;
}
size = C;
}
Word<C>(const Word<C>& copyObg) {
size=copyObg.getSize();
bitCells=copyObg.bitCells;
}
}
I have errors with the copy constructor, on the line of intilizeing the size, I get:
"Multiple markers at this line
- passing 'const Word<16>' as 'this' argument of 'int Word::getSize() [with int C = 16]' discards qualifiers [-
fpermissive]
- Invalid arguments ' Candidates are: int getSize() '"
what is wrong with this ?
thank you

I'd write the class like this:
template <std::size_t N>
class Word
{
std::array<int, N> bit_cells_;
public:
static constexpr std::size_t size = N;
Word() : bit_cells_{} {}
// public functions
};
Note:
No need for a dynamic size, since it's part of the type.
No need for special member functions, since the implicitly defined ones are fine.
Initialize the member array to zero via the constructor-initializer-list.
Template parameter is unsigned, since it represents a count.

What's wrong is that your getSize() is not declared const. Make it so:
int getSize() const { return size; }

Related

Member function of derived class does not care about template argument

I want to simulate a chain of particles either in the up position or the down position. To this end I made a class that inherits from bitset. It looks like:
#include <bitset>
using namespace std;
template <size_t N>
class State : public bitset<N> {
public:
State<N>();
State<N>(size_t b);
long int E();
private:
size_t length;
};
template<unsigned long N>
State<N>::State()
: std::bitset<N>(), length(N)
{}
template<unsigned long N>
State<N>::State(size_t b)
: std::bitset<N>(b), length(N)
{}
Once such an object is instantiated using a certain length, I would like to find the energy associated to such an object. I want to do this
#include "state.h"
long int State::E(){
long int e = 0;
for (size_t i = 1; i != length; ++i)
e += (test[i] == test[i - 1]) ? 1 : -1;
return e;
}
I receive the error
state/state.cc:3:10: error: ‘template<long unsigned int N> class State’ used without template parameters
long int State::E(){
^~~~~
state/state.cc: In function ‘long int E()’:
state/state.cc:5:27: error: ‘length’ was not declared in this scope
for (size_t i = 1; i != length; ++i)
^~~~~~
state/state.cc:6:11: error: ‘test’ was not declared in this scope
e += (test[i] == test[i - 1]) ? 1 : -1;
^~~~
I understand this to mean that the compiler does not recognize that E() is a member function of my class due to a missing template argument. However, I was hoping there is a way that I can call s.E() on a State<20> object for instance. So once the object is instantiated I would like to be able to call E() without having to again specify the size. Is this possible? Thanks in advance!
There are two issues here: defining the member function E() of the class template State<N>, and accessing the test() member function of the dependent base class bitset<N>.
template<size_t N>
long int State<N>::E(){
long int e = 0;
for (size_t i = 1; i != length; ++i)
e += (this->test(i) == this->test(i - 1)) ? 1 : -1;
}
Note both the template<size_t N> and the State<N> as well as the this-> in front of test. See this Q&A for a detailed explanation.
Final note: also be careful: it's test() (parentheses) and operator[] (brackets) in std::bitset.
In the definition of member function of tempalte class, you must specify the template parameters as you did for the constructor.
The error "lenght not declared" should be fixed also by this change.
template <size_t N>
long int State<N>::E(){
long int e = 0;
for (size_t i = 1; i != length; ++i)
e += (test(i) == test(i - 1)) ? 1 : -1;
return e;
}

Efficient Templated-structures in C++

I want to use a templated structure in order to mimic an array of doubles in 4 dimensions, the maximum size for each dimension is know in compilation time. Therefore, I think that using templates structure will give a chance to gain performance. You can find my attempt for the implementation bellow.
The code compiles unless that I attempt to instantiate one structure. I don't understand what is the problem with the code bellow, suggestions will be very appreciated.
Even more, I want to do two improvements if possible: 1) I want to be capable of use data of type float and of type double 2) Will be fancy to have some kind of overloaded operator that enables to assign values to the records of data in a similar way as T(N,L,M,J)=val in place of having to use T.assign(N,L, M,J,value). Again, suggestions will be very appreciated.
My aim is to fill the data in T_4D as fast as possible.
#include <iostream>
#include <cstring> // for memset
using namespace std;
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10,double *data=NULL>
struct T_4D {
enum {SIZE = dim_N*dim_L*dim_M*dim_J };
enum {LEN1 = dim_N };
enum {LEN2 = dim_L };
enum {LEN3 = dim_M };
enum {LEN4 = dim_J };
static void create()
{
data=(double *)malloc(SIZE*sizeof(double));
memset(data, 0.0, SIZE*sizeof(*data));
}
static size_t multi_index(const size_t N) {
return N;
}
static size_t multi_index(const size_t N,const size_t L) {
return L*dim_N + N;
}
static size_t multi_index(const size_t N,const size_t L, const size_t M) {
return (M*dim_L + L)*dim_N + N;
}
static size_t multi_index(const size_t N,const size_t L, const size_t M,const size_t J) {
return ((J*dim_M + M)*dim_L + L)*dim_N + N;
}
double operator()(size_t N,size_t L, size_t M, size_t J){
return data[multi_index(N,L,M,J)];
}
static void assign(size_t N,size_t L, size_t M, size_t J,double value){
data[multi_index(N,L,M,J)]=value;
}
};
int main()
{
double *instance;
T_4D<3,3,3,10,instance> T;
T.create();
return 0;
}
The compilation errors are:
./main.cpp: In function ‘int main()’:
./main.cpp:49:17: error: the value of ‘instance’ is not usable in a constant expression
T_4D<3,3,3,10,instance> T;
^
./main.cpp:48:11: note: ‘instance’ was not declared ‘constexpr’
double *instance;
^
./main.cpp:49:25: error: ‘instance’ is not a valid template argument because ‘instance’ is a variable, not the address of a variable
T_4D<3,3,3,10,instance> T;
^
./main.cpp:50:5: error: request for member ‘create’ in ‘T’, which is of non-class type ‘int’
T.create();
^
Makefile:197: recipe for target 'obj/main.o' failed
make: *** [obj/main.o] Error 1
If all of your dimensions are known at compile time, there is no need for you to allocate dynamic memory. Simply use:
std::aligned_storage_t<sizeof( T ) * SIZE, alignof( T )> data;
You don't even need to initialize anything since you're working with POD types. If you want to zero the memory out, just use this:
for ( std::size_t i = 0; i < SIZE; ++i )
*( reinterpret_cast<T*>( &data ) + i ) = 0;
This will be the most efficient implementation, since we use static contiguous memory. You'll have to implement proper indexing, but that's not too difficult.
Actually, just use T data[ SIZE ]; or std::array<T, SIZE> data.
Also, remove the double* template parameter, these cannot be changed, so it can't be used for your data.
Using double* data = NULL as a template parameter does not seem right. You can use a double* as a template parameter but you can't assign to it as you are doing with:
data=(double *)malloc(SIZE*sizeof(double));
You can remove that as a template parameter and make it a member variable of the class.
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10>
struct T_4D {
double* data;
...
and then allocate memory for it in the constructor instead of in the static member function.
T_4D() : data(new double[SIZE])
{
memset(data, 0.0, SIZE*sizeof(*data));
}
Remember to follow The Rule of Three and The Rule of Five since you are allocating memory from the heap.
Then, main can simply be:
int main()
{
T_4D<3,3,3,10> T;
return 0;
}

c++ send arguments to union (variable union)

well i cant find how do this, basically its a variable union with params, basic idea, (writed as function)
Ex1
union Some (int le)
{
int i[le];
float f[le];
};
Ex2
union Some
{
int le;
int i[le];
float f[le];
};
obs this don't works D:
maybe a way to use an internal variable to set the lenght but don't works too.
Thx.
No, this is not possible: le would need to be known at compile-time.
One solution would be to use a templated union:
template <int N> union Some
{
int i[N];
float f[N];
};
N, of course, is compile-time evaluable.
Another solution is the arguably more succinct
typedef std::vector<std::pair<int, float>> Some;
or a similar solution based on std::array.
Depending on your use case you could try to simulate a union.
struct Some
{
//Order is important
private:
char* pData;
public:
int* const i;
float* const f;
public:
Some(size_t len)
:pData(new char[sizeof(int) < sizeof(float) ? sizeof(float) : sizeof(int)])
,i ((int*)pData)
,f ((float*)pData)
{
}
~Some()
{
delete[] pData;
}
Some(const Some&) = delete;
Some& operator=(const Some&) = delete;
};
Alternative solution using templates, unique_ptr and explicit casts:
//max_size_of<>: a recursive template struct to evaluate the
// maximum value of the sizeof function of all types passed as
// parameter
//The recursion is done by using the "value" of another
// specialization of max_size_of<> with less parameter types
template <typename T, typename...Args>
struct max_size_of
{
static const std::size_t value = std::max(sizeof(T), max_size_of<Args...>::value);
};
//Specialication for max_size_of<> as recursion stop
template <typename T>
struct max_size_of<T>
{
static const std::size_t value = sizeof(T);
};
//dataptr_auto_cast<>: a recursive template struct that
// introduces a virtual function "char* const data_ptr()"
// and an additional explicit cast operator for a pointer
// of the first type. Due to the recursion a cast operator
// for every type passed to the struct is created.
//Attention: types are not allowed to be duplicate
//The recursion is done by inheriting from of another
// specialization of dataptr_auto_cast<> with less parameter types
template <typename T, typename...Args>
struct dataptr_auto_cast : public dataptr_auto_cast<Args...>
{
virtual char* const data_ptr() const = 0; //This is needed by the cast operator
explicit operator T* const() const { return (T*)data_ptr(); } //make it explicit to avoid unwanted side effects (manual cast needed)
};
//Specialization of dataptr_auto_cast<> as recursion stop
template <typename T>
struct dataptr_auto_cast<T>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
//union_array<>: inherits from dataptr_auto_cast<> with the same
// template parameters. Also has a static const member "blockSize"
// that indicates the size of the largest datatype passed as parameter
// "blockSize" is used to determine the space needed to store "size"
// elements.
template <typename...Args>
struct union_array : public dataptr_auto_cast<Args...>
{
static const size_t blockSize = max_size_of<Args...>::value;
private:
std::unique_ptr<char[]> m_pData; //std::unique_ptr automatically deletes the memory it points to on destruction
size_t m_size; //The size/no. of elements
public:
//Create a new array to store "size" elements
union_array(size_t size)
:m_pData(new char[size*blockSize])
,m_size(size)
{
}
//Copy constructor
union_array(const union_array<Args...>& other)
:m_pData(new char[other.m_size*blockSize])
,m_size(other.m_size)
{
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
//Move constructor
union_array(union_array<Args...>&& other)
:m_pData(std::move(other.m_pData))
,m_size(std::move(other.m_size))
{
}
union_array& operator=(const union_array<Args...>& other)
{
m_pData = new char[other.m_size*blockSize];
m_size = other.m_size;
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
union_array& operator=(union_array<Args...>&& other)
{
m_pData = std::move(other.m_pData);
m_size = std::move(other.m_size);
}
~union_array() = default;
size_t size() const
{
return m_size;
}
//Implementation of dataptr_auto_cast<>::data_ptr
virtual char* const data_ptr() const override
{
return m_pData.get();
}
};
int main()
{
auto a = union_array<int, char, float, double>(5); //Create a new union_array object with enough space to store either 5 int, 5 char, 5 float or 5 double values.
((int*)a)[3] = 3; //Use as int array
auto b = a; //copy
((int*)b)[3] = 1; //Change a value
auto c = std::move(a);// move a to c, a is invalid beyond this point
// std::cout << ((int*)a)[3] << std::endl; //This will crash as a is invalid due to the move
std::cout << ((int*)b)[3] << std::endl; //prints "1"
std::cout << ((int*)c)[3] << std::endl; //prints "3"
}
Explanation
template <typename T, typename...Args>
struct max_size_of
{
static const std::size_t value = std::max(sizeof(T), max_size_of<Args...>::value);
};
template <typename T>
struct max_size_of<T>
{
static const std::size_t value = sizeof(T);
};
max_size_of<> is used to get the largest sizeof() value of all types passed as template paremeters.
Let's have a look at the simple case first.
- max_size_of<char>::value: value will be set to sizeof(char).
- max_size_of<int>::value: value will be set to sizeof(int).
- and so on
If you put in more than one type it will evaluate to the maximum of the sizeof of these types.
For 2 types this would look like this: max_size_of<char, int>::value: value will be set to std::max(sizeof(char), max_size_of<int>::value).
As described above max_size_of<int>::value is the same as sizeof(int), so max_size_of<char, int>::value is the same as std::max(sizeof(char), sizeof(int)) which is the same as sizeof(int).
template <typename T, typename...Args>
struct dataptr_auto_cast : public dataptr_auto_cast<Args...>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
template <typename T>
struct dataptr_auto_cast<T>
{
virtual char* const data_ptr() const = 0;
explicit operator T* const() const { return (T*)data_ptr(); }
};
dataptr_auto_cast<> is what we use as a simple abstract base class.
It forces us to implement a function char* const data_ptr() const in the final class (which will be union_array).
Let's just assume that the class is not abstract and use the simple version dataptr_auto_cast<T>:
The class implements a operator function that returns a pointer of the type of the passed template parameter.
dataptr_auto_cast<int> has a function explicit operator int* const() const;
The function provides access to data provided by the derived class through the data_ptr()function and casts it to type T* const.
The const is so that the pointer isn't altered accidentially and the explicit keyword is used to avoid unwanted implicit casts.
As you can see there are 2 versions of dataptr_auto_cast<>. One with 1 template paremeter (which we just looked at) and one with multiple template paremeters.
The definition is quite similar with the exception that the multiple parameters one inherits dataptr_auto_cast with one (the first) template parameter less.
So dataptr_auto_cast<int, char> has a function explicit operator int* const() const; and inherits dataptr_auto_cast<char> which has a function explicit operator char* const() const;.
As you can see there is one cast operator function implemented with each type you pass.
There is only one exception and that is passing the same template parameter twice.
This would lead in the same operator function being defined twice within the same class which doesn't work.
For this use case, using this as a base class for the union_array, this shouldn't matter.
Now that these two are clear let's look at the actual code for union_array:
template <typename...Args>
struct union_array : public dataptr_auto_cast<Args...>
{
static const size_t blockSize = max_size_of<Args...>::value;
private:
std::unique_ptr<char[]> m_pData;
size_t m_size;
public:
//Create a new array to store "size" elements
union_array(size_t size)
:m_pData(new char[size*blockSize])
,m_size(size)
{
}
//Copy constructor
union_array(const union_array<Args...>& other)
:m_pData(new char[other.m_size*blockSize])
,m_size(other.m_size)
{
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
//Move constructor
union_array(union_array<Args...>&& other)
:m_pData(std::move(other.m_pData))
,m_size(std::move(other.m_size))
{
}
union_array& operator=(const union_array<Args...>& other)
{
m_pData = new char[other.m_size*blockSize];
m_size = other.m_size;
memcpy(m_pData.get(), other.m_pData.get(), other.m_size);
}
union_array& operator=(union_array<Args...>&& other)
{
m_pData = std::move(other.m_pData);
m_size = std::move(other.m_size);
}
~union_array() = default;
size_t size() const
{
return m_size;
}
virtual char* const data_ptr() const override
{
return m_pData.get();
}
};
As you can see union_array<> inherits from dataptr_auto_cast<> using the same template arguments.
So this gives us a cast operator for every type passed as template paremeter to union_array<>.
Also at the end of union_array<> you can see that the char* const data_ptr() const function is implemented (the abstract function from dataptr_auto_cast<>).
The next interesting thing to see is static const size_t blockSize which is initilialized with the maximum sizeof value of the template paremeters to union_array<>.
To get this value the max_size_of is used as described above.
The class uses std::unique_ptr<char[]> as data storage, as std::unique_ptr automatically will delete the space for us, once the class is destroyed.
Also std::unique_ptr is capable of move semantics, which is used in the move assign operator function and the move constructor.
A "normal" copy assign operator function and a copy constructor are also included and copy the memory accordingly.
The class has a constructor union_array(size_t size) which takes the number of elements the union_array should be able to hold.
Multiplying this value with blockSize gives us the space needed to store exactly size elements of the largest template type.
Last but not least there is an access method to ask for the size() if needed.
C++ requires that the size of a type be known at compile time.
The size of a block of data need not be known, but all types have known sizes.
There are three ways around it.
I'll ignore the union part for now. Imagine if you wanted:
struct some (int how_many) {
int data[how_many];
};
as the union part adds complexity which can be dealt with separately.
First, instead of storing the data as part of the type, you can store pointers/references/etc to the data.
struct some {
std::vector<int> data;
explicit some( size_t how_many ):data(how_many) {};
some( some&& ) = default;
some& operator=( some&& ) = default;
some( some const& ) = default;
some& operator=( some const& ) = default;
some() = default;
~some() = default;
};
here we store the data in a std::vector -- a dynamic array. We default copy/move/construct/destruct operations (explicitly -- because it makes it clearer), and the right thing happens.
Instead of a vector we can use a unique_ptr:
struct some {
std::unique_ptr<int[]> data;
explicit some( size_t how_many ):data(new int[how_many]) {};
some( some&& ) = default;
some& operator=( some&& ) = default;
some() = default;
~some() = default;
};
this blocks copying of the structure, but the structure goes from being size of 3 pointers to being size of 1 in a typical std implementation. We lose the ability to easily resize after the fact, and copy without writing the code ourselves.
The next approach is to template it.
template<std::size_t N>
struct some {
int data[N];
};
this, however, requires that the size of the structure be known at compile-time, and some<2> and some<3> are 'unrelated types' (barring template pattern matching). So it has downsides.
A final approach is C-like. Here we rely on the fact that data can be variable in size, even if types are not.
struct some {
int data[1]; // or `0` in some compilers as an extension
};
some* make_some( std::size_t n ) {
Assert(n >= 1); // unless we did `data[0]` above
char* buff = new some[(n-1)*sizeof(int) + sizeof(some)]; // note: alignment issues on some platforms?
return new(buff) some(); // placement new
};
where we allocate a buffer for some of variable size. Access to the buffer via data[13] is practically legal, and probably actually so as well.
This technique is used in C to create structures of variable size.
For the union part, you'll want to create a buffer of char with the right size std::max(sizeof(float), sizeof(int))*N, and expose functions:
char* data(); // returns a pointer to the start of the buffer
int* i() { return reinterpret_cast<int*>(data()); }
float* f() { return reinterpret_cast<float*>(data()); }
you may also need to properly initialize the data as the proper type; in theory, a char buffer of '\0's may not correspond to defined float values or ints that are zero.
I would like to suggest a different approach: Instead of tying the number of elements to the union, tie it outside:
union Some
{
int i;
float f;
};
Some *get_Some(int le) { return new Some[le]; }
Don't forget to delete[] the return value of get_Some... Or use smart pointers:
std::unique_ptr<Some[]> get_Some(int le)
{ return std::make_unique<Some[]>(le); }
You can even create a Some_Manager:
struct Some_Manager
{
union Some
{
int i;
float f;
};
Some_Manager(int le) :
m_le{le},
m_some{std::make_unique<Some[]>(le)}
{}
// ... getters and setters...
int count() const { return m_le; }
Some &operator[](int le) { return m_some[le]; }
private:
int m_le{};
std::unique_ptr<Some[]> m_some;
};
Take a look at the Live example.
It's not possible to declare a structure with dynamic sizes as you are trying to do, the size must be specified at run time or you will have to use higher-level abstractions to manage a dynamic pool of memory at run time.
Also, in your second example, you include le in the union. If what you were trying to do were possible, it would cause le to overlap with the first value of i and f.
As was mentioned before, you could do this with templating if the size is known at compile time:
#include <cstdlib>
template<size_t Sz>
union U {
int i[Sz];
float f[Sz];
};
int main() {
U<30> u;
u.i[0] = 0;
u.f[1] = 1.0;
}
http://ideone.com/gG9egD
If you want dynamic size, you're beginning to reach the realm where it would be better to use something like std::vector.
#include <vector>
#include <iostream>
union U {
int i;
float f;
};
int main() {
std::vector<U> vec;
vec.resize(32);
vec[0].i = 0;
vec[1].f = 42.0;
// But there is no way to tell whether a given element is
// supposed to be an int or a float:
// vec[1] was populated via the 'f' option of the union:
std::cout << "vec[1].i = " << vec[1].i << '\n';
}
http://ideone.com/gjTCuZ

error: Illegal zero sized array

I get this error:
error C2229: class 'GenerateRandNum<int [],int>' has an illegal zero-sized array
In my main, I call my random generator function to input into a empty data set
I call the method in my main like so:
//declare small array
const int smallSize = 20;
int smallArray[smallSize];
// call helper function to put random data in small array
GenerateRandNum <int[], int> genData(smallArray, smallSize);
genData.generate();
Header file
template <class T, class B>
class GenerateRandNum
{
public:
T data;
B size;
GenerateRandNum(T list, B length)
{
data = list;
size = length;
}
void generate();
};
File with method definition
template<class T, class B>
void GenerateRandNum<T, B> ::generate()
{
for (B i = 0; i < size; i++)
{
data[0] = 1 + rand() % size;
}
}
Pointers and arrays are not the same in C/C++. They are two very different things. However, arrays decay into pointers. Most notably in function declarations: The declaration
void foo(int array[7]);
is defined to be equivalent to
void foo(int* array);
That said, all the GenerateRandNum constructor gets, is a int* because that's what T = int [] decays to in the function declaration context. The data member of GenerateRandNum, however, is of type int [] (no decay here), which your compiler assumes to be a zero sized array. Consequently, when you try to assign a pointer to the array, your compiler complains.
You have two options to fix this:
You use an std::vector<> instead, as Marco A. suggests.
You declare your GenerateRandNum class as:
template <class T>
class GenerateRandNum {
public:
T* data;
size_t size;
GenerateRandNum(T* list, size_t length) {
data = list;
size = length;
}
void generate();
};
Note:
I have removed the template parameter for the size type: size_t is guaranteed to be suitable for counting anything in memory, so there is absolutely no point in using anything different. Templating this parameter only obfuscates your code.
There are some problems with your approach:
The first array template parameter can't have its dimension deduced from the argument as n.m. noted, you would need to specify it explicitly:
GenerateRandNum<int[20], int>
There no point in doing
data = list
since in your code sample these are two arrays and you can't assign them directly. You can either copy the memory or specialize your routines/template
You should really consider using a vector of integers, e.g.
template <class T, class B>
class GenerateRandNum
{
public:
T data;
B size;
GenerateRandNum(T list, B length) {
data = list;
size = length;
}
void generate();
};
template<class T, class B>
void GenerateRandNum<T, B> ::generate()
{
srand((unsigned int)time(NULL)); // You should initialize with a seed
for (B i = 0; i < size; i++) {
data[i] = 1 + rand() % size; // I believe you wanted data[i] and not data[0]
}
}
int main(){
//declare small array
const int smallSize = 20;
std::vector<int> smallArray(smallSize);
// call helper function to put random data in small array
GenerateRandNum <std::vector<int>, int> genData(smallArray, smallSize);
genData.generate();
}
Example
I fixed two issues in the code above, take a look at the comments.

C++: initializing template constructor/routine declared in header file?

I have a template defined in my header file as follows:
template<typename T> class BoundedBuffer {
unsigned int size;
T entries[];
public:
BoundedBuffer( const unsigned int size = 10 );
void insert( T elem );
T remove();
};
However, when I try to initialize the constructor:
BoundedBuffer<T>::BoundedBuffer( const unsigned int size = 10 ) size(size) {
// create array of entries
entries = new T[size];
// initialize all entries to null
for(int i = 0; i < size; i++)
entries[i] = null;
}
I get the following error (the first line of the previous code block is 17):
q1buffer.cc:17: error: âTâ was not declared in this scope
q1buffer.cc:17: error: template argument 1 is invalid
q1buffer.cc:17: error: expected initializer before âsizeâ
The right syntax is:
template <typename T>
BoundedBuffer<T>::BoundedBuffer(const unsigned int size) : size(size) {
// create array of entries
entries = new T[size];
// initialize all entries to null
for(int i = 0; i < size; i++)
entries[i] = null;
}
Note that optional parameters should not be declared in functions definitions but ony in functions declarations.
class aaa
{
// declaration
void xxx(int w = 10);
};
// definition
void aaa::xxx(int w)
{
...
}
Note that everything for templated class should stay in H files.
"They must be in the same translation unit. It is quite common in some libraries to separate the template implementation into a .tpp (or some other extension) file that is then included in the .h where the template is declared." as Michael Price said.
Templates are not normal types and they cannot be linked.
They are instantiated only when requested.
Note that constructors fields initializers need the ":" character.
class MyClass
{
public:
int x;
MyClass() : x(10) { /* note that i used : character */ }
};
You have to implement all methods of the template in the header, because users of the template need to be able see those methods to instantiate it for a given type.
Your declaration should be:
template< typename T >
BoundedBuffer<T>::BoundedBuffer( const unsigned int size ) : size( size ) {...}
Note that it also has to be in the header file, as mentioned by #Dean Povey.