#include <iostream>
#include <vector>
#include <memory>
#include <cstddef>
#include <stdexcept>
#include <type_traits>
#include <initializer_list>
template <typename T = int, size_t N = 5>
class MyArray {
private:
T data_[N];
static int count_;
public:
using value_type = T;
using size_type = size_t;
using reference = T&;
using const_reference = const T&;
MyArray() {
for (size_t i = 0; i < N; ++i) data_[i] = T();
++count_;
}
explicit MyArray(const T& val) {
for (size_t i = 0; i < N; ++i) data_[i] = val;
++count_;
}
MyArray(std::initializer_list<T> init) {
size_t i = 0;
for (auto it = init.begin(); it != init.end() && i < N; ++it, ++i) {
data_[i] = *it;
}
for (; i < N; ++i) data_[i] = T();
++count_;
}
MyArray(const MyArray& other) {
for (size_t i = 0; i < N; ++i) data_[i] = other.data_[i];
++count_;
}
template <typename U>
MyArray(const MyArray<U, N>& other) {
for (size_t i = 0; i < N; ++i) {
data_[i] = static_cast<T>(other[i]);
}
++count_;
}
MyArray& operator=(const MyArray& other) {
if (this != &other) {
for (size_t i = 0; i < N; ++i) data_[i] = other.data_[i];
}
return *this;
}
~MyArray() { --count_; }
reference operator[](size_t index) { return data_[index]; }
const_reference operator[](size_t index) const { return data_[index]; }
static constexpr size_t size() { return N; }
T* begin() { return data_; }
T* end() { return data_ + N; }
const T* begin() const { return data_; }
const T* end() const { return data_ + N; }
static int get_count() { return count_; }
template <typename U, size_t M>
friend std::ostream& operator<<(std::ostream& os, const MyArray<U, M>& arr);
};
template <typename T, size_t N>
int MyArray<T, N>::count_ = 0;
template <typename U, size_t M>
std::ostream& operator<<(std::ostream& os, const MyArray<U, M>& arr) {
os << "[ ";
for (size_t i = 0; i < M; ++i) {
os << arr.data_[i] << (i == M-1 ? " " : ", ");
}
os << "]";
return os;
}
template <>
class MyArray<bool, 8> {
private:
unsigned char bits_;
static int count_;
public:
using value_type = bool;
MyArray() : bits_(0) { ++count_; }
explicit MyArray(bool val) : bits_(val ? 0xFF : 0x00) { ++count_; }
~MyArray() { --count_; }
bool operator[](size_t index) const {
return (bits_ >> index) & 1;
}
void set(size_t index, bool val) {
if (val) bits_ |= (1 << index);
else bits_ &= ~(1 << index);
}
static constexpr size_t size() { return 8; }
static int get_count() { return count_; }
friend std::ostream& operator<<(std::ostream& os, const MyArray<bool, 8>& arr) {
os << "[ ";
for (size_t i = 0; i < 8; ++i)
os << arr[i] << (i == 7 ? " " : ", ");
os << "]";
return os;
}
};
int MyArray<bool, 8>::count_ = 0;
template <typename T>
class MyArray<T, 0> {
public:
using value_type = T;
static constexpr size_t size() { return 0; }
T operator[](size_t) const { throw std::out_of_range("empty array"); }
friend std::ostream& operator<<(std::ostream& os, const MyArray<T, 0>&) {
return os << "[ empty ]";
}
};
template <typename T, size_t N>
class MyArray<T*, N> {
private:
T* data_[N];
public:
MyArray() {
for (size_t i = 0; i < N; ++i) data_[i] = nullptr;
}
T*& operator[](size_t idx) { return data_[idx]; }
const T* operator[](size_t idx) const { return data_[idx]; }
static constexpr size_t size() { return N; }
void delete_all() {
for (size_t i = 0; i < N; ++i) {
delete data_[i];
data_[i] = nullptr;
}
}
friend std::ostream& operator<<(std::ostream& os, const MyArray<T*, N>& arr) {
os << "[ ";
for (size_t i = 0; i < N; ++i) {
if (arr.data_[i]) os << *(arr.data_[i]);
else os << "null";
os << (i == N-1 ? " " : ", ");
}
os << "]";
return os;
}
};
template <typename T, size_t N>
class DerivedArray : public MyArray<T, N> {
public:
using Base = MyArray<T, N>;
using Base::Base;
void double_elements() {
for (size_t i = 0; i < Base::size(); ++i) {
(*this)[i] = (*this)[i] + (*this)[i];
}
}
T& operator[](size_t idx) { return Base::operator[](idx); }
const T& operator[](size_t idx) const { return Base::operator[](idx); }
};
template <template <typename, size_t> class Container, typename T, size_t N>
void printContainer(const Container<T, N>& cont) {
std::cout << "Container<" << typeid(T).name() << ", " << N << "> = ";
std::cout << cont << std::endl;
}
template <typename T, size_t N, typename... Args>
MyArray<T, N> make_my_array_impl(Args&&... args) {
static_assert(sizeof...(Args) == N, "wrong number of initializers");
MyArray<T, N> arr;
T init[] = { std::forward<Args>(args)... };
for (size_t i = 0; i < N; ++i)
arr[i] = init[i];
return arr;
}
template <typename T, typename... Args>
auto make_my_array(Args&&... args) -> MyArray<T, sizeof...(Args)> {
return make_my_array_impl<T, sizeof...(Args)>(std::forward<Args>(args)...);
}
int main() {
using namespace std;
MyArray<> defaultArr;
cout << "1. Default MyArray: " << defaultArr << endl;
cout << " count = " << MyArray<>::get_count() << endl;
MyArray<double, 3> doubleArr{1.1, 2.2, 3.3};
cout << "2. MyArray<double,3> with init list: " << doubleArr << endl;
MyArray<int, 3> intArrFromDouble(doubleArr);
cout << "3. Convert from double to int: " << intArrFromDouble << endl;
MyArray<bool, 8> bits;
bits.set(0, true);
bits.set(3, true);
bits.set(7, true);
cout << "4. Full specialization (bool,8): " << bits << " count=" << MyArray<bool,8>::get_count() << endl;
MyArray<int, 0> emptyArr;
cout << "5. Partial specialization (size 0): " << emptyArr << endl;
MyArray<int*, 3> ptrArr;
ptrArr[0] = new int(100);
ptrArr[1] = new int(200);
ptrArr[2] = new int(300);
cout << "6. Partial specialization (T*): " << ptrArr << endl;
ptrArr.delete_all();
DerivedArray<int, 4> derived;
for (size_t i = 0; i < derived.size(); ++i) derived[i] = i + 1;
cout << "7. DerivedArray before double: " << derived << endl;
derived.double_elements();
cout << " after double: " << derived << endl;
printContainer(derived);
printContainer(bits);
cout << "9. Current MyArray<> count (int,5): " << MyArray<>::get_count() << endl;
{
MyArray<float, 2> local;
cout << " inside block, MyArray<float,2> count: " << MyArray<float,2>::get_count() << endl;
}
cout << " after block, MyArray<float,2> count: " << MyArray<float,2>::get_count() << endl;
cout << " MyArray<int,5> count unchanged: " << MyArray<>::get_count() << endl;
auto arrFromVariadic = make_my_array<int>(10, 20, 30, 40);
cout << "10. make_my_array<int>(10,20,30,40): " << arrFromVariadic << endl;
MyArray<long> longArr5;
cout << "11. MyArray<long> (size 5 default): " << longArr5 << endl;
return 0;
}