我有一个代表一些应用程序事件的类。我希望能够为事件设置(并稍后检索)各种属性。这些标识由唯一的std::string
标签识别。
我能够编写下面的代码,但是,由于我对模板不是很熟悉,所以我不能感觉到应该有更好的方法来使用(更多)模板,并摆脱那可怕的void *
。理想情况下,此解决方案还将在编译时进行属性类型检查 - 但我不确定这是否可行。
你有更好的方法吗?
我的代码(暂时忽略内存泄漏):
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));
}
答案 0 :(得分:1)
您可以(应该)使用类型安全的变体模板替换“属性”类,例如Boost.Any或Boost.variant。 你的地图将是(对于boost :: any)
std::unordered_map<std::string, boost::any> attribs_;
是的,你会摆脱void *,就像任何C ++代码一样!