I am implementing a container in c++, a wrapper for an array in fact. I am not sure how to implement a constructor from initializer_list. I end up with this implementation but it seems to me really ugly. So could be an array allocated in a heap initialized by an initializer_list. Or is there an elegant way how to do it?
template <typename T> class sequence {
public:
sequence (size_t n): _data {new T[n]}, _size {n} {};
sequence (std::initializer_list<T> source);
~sequence() { delete[] _data; };
private:
pointer _data;
size_type _size;
};
//Initializer list constructor
template <class T> sequence<T>::sequence (std::initializer_list<T> source)
: sequence(source.size()) {
auto iterator = source.begin();
for ( int i=0; i < _size; i++) {
_data[i] = *iterator;
++iterator;
}
};
An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T .
Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.
Static Data Member Initialization in C++ For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator, then the variable name. Now we can assign some value.
Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.
Depends on what you're trying to do.
If you're actually needing to use a sequence with bounded size, as determined at compile-time, then use std::array<T,std::size_t>
, which is a wrapper around a C-style array (like what you are implementing), introduced in C++11.
However, as you said in one of your comments, you're doing this mostly for educational purposes. In that case, what you have is decent. The syntax could be cleaned up a little. Consider:
//Initializer list constructor
template <class T>
sequence<T>::sequence (std::initializer_list<T> source)
: sequence(source.size())
{
auto it = source.begin();
auto const e = source.cend();
auto d = data_;
while (it != e) {
*d++ = *it++;
}
};
That way you don't explicitly rely on the size()
. You could consider making things more efficient by turning the it
and e
iterators into "move" iterators:
auto it = std::make_move_iterator(source.begin());
auto e = std::make_move_iterator(source.end());
That way, whenever it's dereferenced, its value is cast to an rvalue reference, allowing a move assignment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With