#include <iostream>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>

namespace util
{
	template<typename T, typename... R>
	struct ordered_set : private std::vector<T, R...>
	{
	private:
		using base = std::vector<T, R...>;
		using set = std::set<T, R...>;
	public:
		using typename base::value_type;
		using typename base::allocator_type;
		using typename base::size_type;
		using typename base::difference_type;
		using typename base::reference;
		using typename base::const_reference;
		using typename base::pointer;
		using typename base::const_pointer;
		using typename base::iterator;
		using typename base::const_iterator;
		using typename base::reverse_iterator;
		using typename base::const_reverse_iterator;

		using base::get_allocator;
		using base::at;
		using base::operator[];
		using base::front;
		using base::back;
		using base::data;
		using base::begin;
		using base::cbegin;
		using base::end;
		using base::cend;
		using base::rbegin;
		using base::crbegin;
		using base::rend;
		using base::crend;
		using base::empty;
		using base::size;

		explicit ordered_set(typename base::allocator_type const &alloc = typename base::allocator_type())
		: base(alloc)
		{
		}
		template<typename Iter>
		ordered_set(Iter first, Iter last, typename base::allocator_type const &alloc = typename base::allocator_type())
		: base(alloc)
		{
			for(set s; first != last; ++first)
			{
				if(s.insert(*first).second)
				{
					base::push_back(*first);
				}
			}
		}
		ordered_set(std::initializer_list<T> init, typename base::allocator_type const &alloc = typename base::allocator_type())
		: ordered_set(init.begin(), init.end(), alloc)
		{
		}

		friend bool operator==(ordered_set const &a, ordered_set const &b){ return static_cast<base>(a) == static_cast<base>(b); }
		friend bool operator!=(ordered_set const &a, ordered_set const &b){ return static_cast<base>(a) != static_cast<base>(b); }
		friend bool operator< (ordered_set const &a, ordered_set const &b){ return static_cast<base>(a) <  static_cast<base>(b); }
		friend bool operator<=(ordered_set const &a, ordered_set const &b){ return static_cast<base>(a) <= static_cast<base>(b); }
		friend bool operator> (ordered_set const &a, ordered_set const &b){ return static_cast<base>(a) >  static_cast<base>(b); }
		friend bool operator>=(ordered_set const &a, ordered_set const &b){ return static_cast<base>(a) >= static_cast<base>(b); }
	};
}

int main()
{
	std::set<std::string> a1 {"a", "b"};
	std::set<std::string> b1 {"b", "a"};
	std::cout << std::boolalpha << (a1 == b1) << std::endl;

	std::unordered_set<std::string> a2 {"a", "b"};
	std::unordered_set<std::string> b2 {"b", "a"};
	std::cout << std::boolalpha << (a2 == b2) << std::endl;

	util::ordered_set<std::string> a3 {"a", "b"};
	util::ordered_set<std::string> b3 {"b", "a"};
	std::cout << std::boolalpha << (a3 == b3) << std::endl;
}
