#include <iostream>
#include <vector>
#include <memory>
#include <cstddef>
#include <stdexcept>
#include <type_traits>
#include <initializer_list>   // for demonstrating optional initializer_list constructor

// ========================== 1. Basic class template (with default template parameters) ==========================
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&;

    // Default constructor
    MyArray() {
        for (size_t i = 0; i < N; ++i) data_[i] = T();
        ++count_;
    }

    // Fill with a single value
    explicit MyArray(const T& val) {
        for (size_t i = 0; i < N; ++i) data_[i] = val;
        ++count_;
    }

    // Added: initializer_list constructor for convenient list initialization
    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;
        }
        // Default-initialize remaining elements if initializer list is shorter
        for (; i < N; ++i) data_[i] = T();
        ++count_;
    }

    // Copy constructor
    MyArray(const MyArray& other) {
        for (size_t i = 0; i < N; ++i) data_[i] = other.data_[i];
        ++count_;
    }

    // Member function template: allow conversion from other MyArray types
    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;
}

// ========================== 2. Full specialization ==========================
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;

// ========================== 3. Partial specialization: size 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 ]";
    }
};

// ========================== 4. Partial specialization: pointer type ==========================
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;
    }
};

// ========================== 5. Inheritance example ==========================
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); }
};

// ========================== 6. Template template parameter ==========================
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;
}

// ========================== 7. Variadic template helper ==========================
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)...);
}

// ========================== main function ==========================
int main() {
    using namespace std;

    // 1. Default construct
    MyArray<> defaultArr;
    cout << "1. Default MyArray: " << defaultArr << endl;
    cout << "   count = " << MyArray<>::get_count() << endl;

    // 2. initializer_list constructor (newly added constructor)
    MyArray<double, 3> doubleArr{1.1, 2.2, 3.3};
    cout << "2. MyArray<double,3> with init list: " << doubleArr << endl;

    // 3. Member function template: type conversion
    MyArray<int, 3> intArrFromDouble(doubleArr);
    cout << "3. Convert from double to int: " << intArrFromDouble << endl;

    // 4. Full specialization MyArray<bool,8>
    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;

    // 5. Partial specialization size 0
    MyArray<int, 0> emptyArr;
    cout << "5. Partial specialization (size 0): " << emptyArr << endl;

    // 6. Partial specialization pointer elements
    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();

    // 7. Inheritance
    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;

    // 8. Template template parameter
    printContainer(derived);
    printContainer(bits);

    // 9. Static member count
    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;

    // 10. Variadic template construction
    auto arrFromVariadic = make_my_array<int>(10, 20, 30, 40);
    cout << "10. make_my_array<int>(10,20,30,40): " << arrFromVariadic << endl;

    // 11. Default template parameter instantiation
    MyArray<long> longArr5;
    cout << "11. MyArray<long> (size 5 default): " << longArr5 << endl;

    return 0;
}

results matching ""

    No results matching ""