#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <deque>
#include <vector>

using std::begin;
using std::end;

class NameCollection
{
public:
    typedef std::vector<std::pair<bool, std::string>> container_type;

    // This is an ad hoc attempt at an iterator proxy; I wouldn't take the 
    // iterator stuff too seriously as any sort of example code.
    struct const_iterator
    {
        const_iterator(container_type::const_iterator it) : _iterator(it) {}

        std::string operator->() const { return _iterator->second;}
        std::string operator*() const { return _iterator->second;}

        const_iterator& operator++() { ++_iterator; return *this;}
        const_iterator operator++(int) { const_iterator result(*this); ++_iterator; return result; }

        bool operator==(const const_iterator& it) const { return _iterator == it._iterator;}
        bool operator!=(const const_iterator& it) const { return !(*this == it);}

        operator container_type::const_iterator() { return _iterator; }
    private:
        container_type::const_iterator _iterator;
    };

    friend NameCollection::const_iterator begin(const NameCollection&);
    friend NameCollection::const_iterator end(const NameCollection&);

    std::vector<std::string> getSelected() const;

    unsigned size() const {return _names.size();}

    void add(const std::string& s);
    void select(const std::string& s);
    bool selected(const std::string& s) const;

    void eraseSelected();

    std::string operator [](unsigned index) const { return _names[index].second ; }

private:

    container_type::iterator _find(const std::string& s) const 
    {
        container_type & names = const_cast<container_type&>(_names); // compiler barfs if const_iterators are used.  TODO:  Research.
        return std::find_if(begin(names), end(names), [&](const container_type::value_type& value) { return value.second == s; });
    }

    container_type _names;
};

std::vector<std::string> NameCollection::getSelected() const
{
    std::vector<std::string> selected;

    for (auto & name : _names)
        if (name.first)
            selected.push_back(name.second);

    return selected;
}

void NameCollection::add(const std::string& s)
{
    if (_find(s) == end(_names))
        _names.emplace_back(false, s);
}

void NameCollection::select(const std::string& s)
{
    auto it = _find(s);

    if (it != end(_names))
        it->first = true;
}

bool NameCollection::selected(const std::string& s) const
{
    auto it = _find(s);
    return it == end(_names) ? false : it->first;
}

void NameCollection::eraseSelected()
{
    auto it = begin(_names);

    while (it != end(_names))
    {
        if (it->first)
            it = _names.erase(it);
        else
            ++it;
    }
}

NameCollection::const_iterator begin(const NameCollection& coll)
{
    return begin(coll._names);
}

NameCollection::const_iterator end(const NameCollection& coll)
{
    return end(coll._names);
}

void print(const NameCollection& nc, std::ostream& os = std::cout)
{
    for (const auto name : nc)
        std::cout << std::setw(2) << (nc.selected(name) ? "*" : "") << ' ' << name << '\n';
}

int main()
{
    NameCollection coll;

    for (char i = 'a'; i <= 'd'; ++i)
    {
        for (char j = 'a'; j <= 'd'; ++j)
            coll.add(std::string(1, i) + j);
    }

    std::cout << "Original:\n";
    print(coll);


    for (unsigned i = 0; i < coll.size(); i += 3)
        coll.select(coll[i]);

    std::cout << "\nAfter selection:\n";
    print(coll);

    coll.eraseSelected();

    std::cout << "\nAfter erase:\n";
    print(coll);
}