#pragma once #include <stdafx.h> //Concept constraining a type to have a .get() method. template<typename T> concept unique_handle = requires { { std::declval<T>().get() }; //-> std::same_as<decltype(*std::declval<T>())>; }; template<typename T> struct unique_handle_type { using type = T; }; //Requires a type to have a ::element_type alias. template<typename T> requires unique_handle<T> struct unique_handle_type<T> { using type = T::element_type; }; //Not every type has a pointer that is functionally equivalent, i.e file handles. template<typename Elem, typename Deleter> struct unique_handle_type<std::unique_ptr<Elem, Deleter>> { using type = std::unique_ptr<Elem, Deleter>::pointer; }; //Requires that std::hash<T> overload is provided for the given type. template<typename T> concept Hashable = requires(T a) { { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>; }; template<Hashable Key = std::string, typename map_value = std::any> class ConstrainedMap { //Type aliases using map_type = typename std::unordered_map<Key, map_value>; using iterator = typename map_type::iterator; using mapped_type = typename map_type::mapped_type; using handle_element_type = typename unique_handle_type<map_value>::type; //helper function to extract iterator to mapped value. map_type hash_table; iterator found_value_iter(const std::string& value) { return hash_table.find(value); }; public: //Get overload that requires an unique handle handle_element_type Get(const std::string& name) requires(unique_handle<map_value>) { return found_value_iter(name)->second.get(); }; //Add overload that requires a unique handle handle_element_type Add(const std::string& name, map_value& resource) requires(unique_handle<map_value>) { hash_table[name] = std::move(resource); return hash_table[name].get(); }; //Add overload that requires a unique handle and takes an r-value ref handle_element_type Add(const std::string& name, map_value&& resource) requires(unique_handle<map_value>) { hash_table[name] = std::move(resource); return hash_table[name].get(); }; //Get overload that returns a reference to the value and that the held value is not an unique handle. mapped_type& Get(const std::string& name) requires(not(unique_handle<map_value>)) { return found_value_iter(name)->second; }; //Add overload that requires the mapped valuee to not be an unique handle. mapped_type& Add(const std::string& name, map_value resource) requires(not(unique_handle<map_value>)) { hash_table[name] = resource; return hash_table[name]; }; bool Exists(const std::string& name) { return found_value_iter(name) != hash_table.end(); } };