Custom array class: constructor to initialize a list
I'm working on a custom array class in C ++ (as a stand alone exercise) and I'm not sure how to create a constructor that allows me to do things line by line:
#include "array.h"
#include <iostream>
int main()
{
array<int> test = {1, 2, 3, 4};
std::cout << test(1) << std::endl;
return 0;
}
The error the compiler (VS Express 2013) gives me is "no instance of the constructor array :: array [with T = int]" match the argument list. Argument types: (int, int, int, int).
I'm not sure what the constructor is being called that takes an enumeration of a set of elements. I know I overloaded correctly operator()(const int&)
. I also know that this (for some reason not clear to me) works:
#include "array.h"
#include <iostream>
int main()
{
array<char> test = "abcd";
std::cout << test(1) << std:: endl; // prints 'a', as expected.
std::cout << test(4) << std::endl; // prints 'd', as expected.
return 0;
}
This is achieved with a constructor array(const T[])
: would there be a similar solution for the case array<int> test = {1, 2, 3, ..., n}
?
Thanks in advance for any recommendations.
EDIT: Including the below code if helpful.
template<typename T>
class array
{
public:
typedef T* iterator;
typedef const T* const_iterator;
private:
iterator head;
unsigned long elems;
public:
array()
: head(nullptr)
, elems(0) {}
array(const unsigned long &size)
: head(size > 0 ? new T[size] : nullptr)
, elems(size) {}
array(const T[]);
array(const array&);
~array() { delete[] head; }
iterator begin() const { return head; }
iterator end() const { return head != nullptr ? &head[elems] : nullptr; }
unsigned long size() const { return elems; }
array& operator=(const array&);
T& operator()(const unsigned long&);
};
template<typename T>
array<T>::array(const T rhs[])
{
unsigned long size = sizeof(rhs) / sizeof(T);
head = new T[size];
iterator pointer = begin();
for (const_iterator i = &rhs[0]; i != &rhs[0] + size; i++)
*pointer++ = *i;
}
template<typename T>
array<T>::array(const array<T> &rhs)
{
head = new T[rhs.size()];
iterator pointer = begin();
for (const_iterator i = rhs.begin(); i != rhs.end(); i++)
*pointer++ = *i;
}
template<typename T>
array<T>& array<T>::operator=(const array<T> &rhs)
{
if (this != &rhs)
{
delete[] head;
head = new T[rhs.size()];
iterator pointer = begin();
for (const_iterator i = rhs.begin(); i != rhs.end(); i++)
*pointer++ = *i;
}
return *this;
}
template<typename T>
T& array<T>::operator()(const unsigned long &index)
{
if (index < 1 || index > size())
{
// Add some error-handling here.
}
return head[index - 1];
}
source to share
#include <initializer_list>
// ...
template <typename T>
class array
{
// ...
array(std::initializer_list<T> il);
// ...
template <typename T>
array<T>::array(std::initializer_list<T> il)
{
unsigned long size = il.size();
head = new T[size];
iterator pointer = begin();
for (const T& i : il)
*pointer++ = i;
}
// ...
array<int> test = {1, 2, 3, 4};
Recommended improvements:
-
array(const T rhs[]);
is equivalentarray(const T* rhs);
, that is, a pointer, which means the expressionsizeof(rhs) / sizeof(T)
won't give you the number of elements. If you need a custom constructor forconst char*
, consider either a whole specializationarray<char>
, or at least disable that constructor from overload resolution ifT
notchar
-
head = new T[size];
default - initializes all elements (calls the default constructor for each instance of the typeT
). Then you call the assignment operator:*pointer++ = *i;
. This can be improved by using a new location, such as::new ((void*)ptr) T(*i);
whereptr
is a pointer to a raw, uninitialized memory buffer, for example,new char[sizeof(T)*size]
or returned from .get_temporary_buffer
And if you're wondering why the following works array<char> test = { "abcd" };
with the current implementation , then here's the explanation:
-
array<T>
the class has a constructor takingconst T[]
whichT=char
is instantiated asarray<char>::array(const char*)
. -
List initialization can be used to call the constructor of objects.
-
The constructor is
const T[]
not explicit, which means that you can use the copy initialization syntax as shown below:array<char> test = { "test" };
-
The expression
sizeof(rhs) / sizeof(T)
, although not valid as explained above, forT=char
evaluatessizeof(char*) / sizeof(char)
to that (most likely)4 / 1 = 4
. -
Yours
"test"
used for initialization has exactly 4 letters, your luck.
source to share