#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>

template <typename Key, typename Value>
class VectorMap {
    std::vector<Key> keys_;
    std::vector<Value> values_;

    static_assert(std::is_default_constructible<Value>::value, "Value should have the default constructor");
    static_assert(std::is_default_constructible_v<Value>, "Value should have the default constructor");

public:
    using K = Key;
    using V = Value;
    template <typename T>
    using iterator = typename std::vector<T>::iterator;

    void insert(const Key& k, const Value& v) {
        keys_.emplace_back(k);
        values_.emplace_back(v);
    }

    static constexpr bool isIntKey() {
        // if (std::is_integral_v<Key>) {
        if (std::is_same_v<Key, int>) {
            return true;
        }
        return false;
    }

    Value& operator[](const Key& k);
    Value& at(const Key& k);

    static constexpr bool is_int_key = std::is_same_v<Key, int>;
};

template <typename Key, typename Value>
Value& VectorMap<Key, Value>::operator[](const Key& k) {
    auto it = std::find(std::begin(keys_), std::end(keys_), k);
    if (it == std::end(keys_)) {
        keys_.emplace_back(k);
        values_.emplace_back(Value{});
        return values_.back();
    }
    auto dist = std::distance(keys_.begin(), it);
    return values_[dist];
}

template <typename Key, typename Value>
Value& VectorMap<Key, Value>::at(const Key& k) {
    auto it = std::find(std::begin(keys_), std::end(keys_), k);
    if (it == std::end(keys_)) {
        throw std::out_of_range("This key does not exist");
    }
    auto dist = std::distance(keys_.begin(), it);
    return values_[dist];
}


template <typename ValueType>
class VectorMap<bool, ValueType> {      // specialization
    static_assert(std::is_default_constructible<ValueType>::value,
                  "ValueType must have the default constructor");

    ValueType t_;
    ValueType f_;

public:
    static constexpr bool is_int_key = false;  // type_traits #2

    VectorMap() {
        std::cout << "bool specialization used\n";
    }

    void insert(bool key, ValueType&& value) {
        if (key) {
            t_ = value;
        } else {
            f_ = value;
        }
    }

    ValueType& operator[](bool key) {
        if (key) {
            return t_;
        }
        return f_;
    }

    ValueType& at(bool key) {
        if (key) {
            return t_;
        }
        return f_;
    }
};

template<typename T>
constexpr bool is_int_key_v = T::is_int_key;

template <typename Key, typename Value>
constexpr bool is_int_key_v1 = VectorMap<Key,Value>::is_int_key;

int main() {
    VectorMap<int, char> map;
    // VectorMap<int, char>::iterator<K> k;
    map.insert(1, 'c');
    std::cout << map[1] << '\n';
    map[1] = 'e';                 // replaces value under 1
    std::cout << map[1] << '\n';  // prints 'e'
    // map.at(2);              // throw std::out_of_range
    std::cout << std::boolalpha << map.isIntKey() << '\n';
    std::cout << std::boolalpha << map.is_int_key << '\n';

    VectorMap<char, char> map3;
    std::cout << std::boolalpha << map3.isIntKey() << '\n';

    VectorMap<bool, int> map4;
    map4.insert(true, 3);
    map4.insert(false, 0);
    std::cout << map4[true] << '\n';
    map4[true] = 10;                 // replaces value under 1
    std::cout << map4[true] << '\n';  // prints 'e'
    std::cout << std::boolalpha << is_int_key_v<decltype(map4)> << '\n';
    std::cout << std::boolalpha << is_int_key_v<decltype(map)> << '\n';
    std::cout << std::boolalpha << is_int_key_v<K> << '\n';

    std::vector<int> v{1, 2, 3};
    find(begin(v), end(v), 2);

    return 0;
}