#include <map>
#include <string>
#include <iostream>

template<typename T>
struct disable_default
{    
	T& get_default()
	{
		throw 1;
	}
    
    const T& get_default() const
    {
        throw 1;
    }
};

template<typename T>
struct enable_default
{
	template<typename Value>
	enable_default(Value&& def_value) : default_value(std::forward<Value>(def_value))
	{
	}
	
	const T& get_default() const
	{
		return default_value;
	}
	
	T& get_default()
	{
		return default_value;
	}
	
private:
	T default_value;		
};

template<typename K, typename T, template <typename> class default_policy = enable_default, typename key_comp = std::less<K>>
struct selector : public default_policy<T>
{		
	template<typename Value>
	selector(Value&& def_value) : default_policy<T>(std::forward<Value>(def_value))
	{
	}
	
	selector()
	{	
	}
				
	struct selector_proxy
	{
		selector_proxy(std::map<K,T, key_comp>& sel_map, const K& pKey) : selector_map(sel_map), key(pKey)
		{
		}
		
		template<typename Val>
		selector_proxy& operator=(Val&& pValue)
		{
			auto it = selector_map.find(key);
			if ( it != end(selector_map) )
			{
				it->second = std::forward<Val>(pValue);
			}
			else
			{
				selector_map.insert(std::make_pair(key, std::forward<Val>(pValue)));
			}
		}
				
	private:
		std::map<K,T,key_comp>& selector_map;	
		const K& key;
	};
	
	selector_proxy at(const K& key)
	{
		return selector_proxy(selector_map, key);
	}
		
	T& get(const K& key)
	{
		return const_cast<T&>(static_cast<const selector*>(this)->get(key));
	}
	
	const T& get(const K& key) const
	{
		auto it = selector_map.find(key);
		if ( it != end(selector_map) )
		{
			return it->second;
		}
		else
		{
			return default_policy<T>::get_default();
		}
	}
	
private:
	std::map<K,T,key_comp> selector_map;
};

using namespace std;

int main()
{
    selector<string, int> d_sel_1(0);
    d_sel_1.at("one") = 1;
    d_sel_1.at("two") = 2;
    cout << d_sel_1.get("one") << endl;
    cout << d_sel_1.get("three") << endl;
    
    selector<string, int, disable_default> nd_sel {};
    try 
    {
        cout << nd_sel.get("one") << endl;
    }
    catch(...)
    {
        cout << "not found" << endl;
    }
}