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];
}

      

+3


source to share


1 answer


#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};

      

DEMO


Recommended improvements:



  • array(const T rhs[]);

    is equivalent array(const T* rhs);

    , that is, a pointer, which means the expression sizeof(rhs) / sizeof(T)

    won't give you the number of elements. If you need a custom constructor for const char*

    , consider either a whole specialization array<char>

    , or at least disable that constructor from overload resolution if T

    notchar

  • head = new T[size];

    default - initializes all elements (calls the default constructor for each instance of the type T

    ). Then you call the assignment operator: *pointer++ = *i;

    . This can be improved by using a new location, such as ::new ((void*)ptr) T(*i);

    where ptr

    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 taking const T[]

    which T=char

    is instantiated as array<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, for T=char

    evaluates sizeof(char*) / sizeof(char)

    to that (most likely) 4 / 1 = 4

    .

  • Yours "test"

    used for initialization has exactly 4 letters, your luck.

+4


source







All Articles