I have a class that represents some application event. I want to be able to set (and later retrieve) various attributes to the event. These are identified by a unique std::string
label.
I was able to write the code below, which works, but, as I'm not very experienced with templates, I can't shake the feeling that there should be a better way to do this with (more) templates, and get rid of that hideous void *
. Ideally, this solution will also do the attribute type checking at compile-time - but I'm not sure if that's possible.
Do you have a better way to do this?
My code (ignoring the memory leak for now):
class Event final
{
public:
Event(EventType type) : type_(type) {}
template <typename T>
void addAttribute(std::string const &name, T value);
template <typename T>
void getAttribute(std::string const &name, T &value) const;
private:
EventType type_;
struct Attribute
{
std::type_index type;
void *ptr;
};
std::unordered_map<std::string, Attribute> attribs_;
};
template <typename T>
inline void Event::addAttribute(std::string const &name, T value)
{
Attribute atr = { typeid(T), new T(value) };
auto res = attribs_.insert({ name, atr });
if (std::get<1>(res) == false)
throw std::runtime_error("Event::addAttribute: unordered_map insertion failed.");
}
template <typename T>
inline void Event::getAttribute(std::string const &name, T &value) const
{
Attribute atr = attribs_.at(name);
if (atr.type != typeid(T))
throw std::runtime_error("Event::getAttribute: wrong attribute type requested.");
value = *(static_cast<T *>(atr.ptr));
}
You can (should) replace your "Attribute" class by a type safe, variant template, such as Boost.Any or Boost.variant . Your map would be (for boost::any )
std::unordered_map<std::string, boost::any> attribs_;
And yes, you would get rid of the void*, as any C++ code should!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.