Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
/* Copyright © 2013 Kővágó, Zoltán
* Released under WTFPL 2.0, http://www.wtfpl.net/
* It comes without any warranty, to the extent permitted by applicable law.
*/
#ifndef TAGGED_CONTAINER_HPP
#define TAGGED_CONTAINER_HPP
#pragma once
#include <memory>
#include <typeindex>
#include <unordered_map>
#include <boost/optional.hpp>
struct TagBase { virtual ~TagBase() = 0; };
inline TagBase::~TagBase() = default;
template <typename T>
struct Tag : public TagBase
{
typedef T Type;
Tag(const Tag&) = delete;
Tag& operator=(const Tag&) = delete;
template <typename... Args>
Tag(Args&&... args) : val(std::forward<Args>(args)...) {}
T val;
};
class TaggedContainer final
{
public:
template <typename T>
const typename T::Type& Get() const
{
EnsureTag<T>();
return static_cast<Tag<typename T::Type>&>(*map.at(typeid(T))).val;
}
template <typename T>
typename T::Type& Get()
{
EnsureTag<T>();
return static_cast<Tag<typename T::Type>&>(*map.at(typeid(T))).val;
}
template <typename T>
typename T::Type& DefaultGet()
{
EnsureTag<T>();
auto& r = map[typeid(T)];
if (!r) r.reset(new Tag<typename T::Type>());
return static_cast<Tag<typename T::Type>&>(*r).val;
}
template <typename T>
boost::optional<const typename T::Type&> MaybeGet() const
{
EnsureTag<T>();
auto it = map.find(typeid(T));
if (it == map.end()) return {};
else return static_cast<Tag<typename T::Type>&>(*map.at(typeid(T))).val;
}
template <typename T, typename... Args>
void Set(Args&&... args)
{
EnsureTag<T>();
map[typeid(T)].reset(new Tag<typename T::Type>(std::forward<Args>(args)...));
}
template <typename T>
void Erase()
{
EnsureTag<T>();
map.erase(typeid(T));
}
private:
template <typename T>
static inline void EnsureTag()
{
static_assert(std::is_base_of<Tag<typename T::Type>, T>::value,
"Do not use Tag directly!");
}
std::unordered_map<std::type_index, std::unique_ptr<TagBase>> map;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment