英文:
C++ Replace enum with instances of class. Avoid heap allocation
问题
我想用类的实例来替代这个枚举:
enum{ eTagA, eTagB,...}
。
这允许添加新的标签,而无需修改枚举。
我有以下代码:
#include <memory>
#include <list>
struct TagBase {
bool operator== (const TagBase& other) const {
return typeid(*this) == typeid(other);
}
bool operator!= (const TagBase& other) const {
return !(*this == other);
}
virtual ~TagBase() = default;
};
bool operator== (const std::unique_ptr<TagBase>& lhs, const TagBase& base) {
return base == *(lhs.get());
}
class Namespace {
public:
template<typename T>
void AddTag() {
tags.push_back(std::unique_ptr<T>(new T()));
}
bool HasTag(const TagBase& tag) const {
return std::find_if(tags.begin(), tags.end(), [&tag](const std::unique_ptr<TagBase>& ptr) {
return *ptr == tag;
}) != tags.end();
}
private:
// 使用 std::unique_ptr 是唯一的方式吗?
std::list<std::unique_ptr<TagBase>> tags;
};
struct TagA: public TagBase {};
struct TagB: public TagBase {};
struct TagC: public TagBase {};
int main (int argc, const char* argv[])
{
Namespace nm;
nm.AddTag<TagA>();
nm.AddTag<TagB>();
assert(nm.HasTag(TagA{}));
assert(nm.HasTag(TagB{}));
assert(nm.HasTag(TagC{}) == false);
}
它可以工作,但我对以下几点有一些想法:
- 在这种情况下使用 "typeid" 是否适当?这是可移植的吗?
- 我不能在 "std:list" 中使用原始的 TagBase 类,因为会发生切片问题。我能否避免使用 "unique_ptr",因为它涉及堆分配?
- 也许有更好的模式来完成这个任务?
我还尝试过强烈使用模板(std::is_same 等),但没有得到合适的解决方案。
英文:
I want to replace this enum:
enum{ eTagA, eTagB,...}
.
With instances of classes. This allows to append new tags, without modifying the enum.
I've got following code:
#include <memory>
#include <list>
struct TagBase {
bool operator== (const TagBase& other) const {
return typeid(*this) == typeid(other);
}
bool operator!= (const TagBase& other) const {
return !(*this == other);
}
virtual ~TagBase() = default;
};
bool operator== (const std::unique_ptr<TagBase>& lhs, const TagBase& base) {
return base == *(lhs.get());
}
class Namespace {
public:
template<typename T>
void AddTag() {
tags.push_back(std::unique_ptr<T>(new T()));
}
bool HasTag(const TagBase& tag) const {
return std::find(std::begin(tags), std::end(tags), tag) != tags.end();
}
private:
// using of std::unique_ptr is the only way?
std::list<std::unique_ptr<TagBase>> tags;
};
struct TagA: public TagBase {};
struct TagB: public TagBase {};
struct TagC: public TagBase {};
int main (int argc, const char* argv[])
{
Namespace nm;
nm.AddTag<TagA>();
nm.AddTag<TagB>();
assert(nm.HasTag(TagA{}));
assert(nm.HasTag(TagB{}));
assert(nm.HasTag(TagC{}) == false);
}
It works, but I have some thoughts about:
- Using "typeid" in this context is appropriate? Is this portable?
- I can't use raw TagBase class in "std:list" because of slicing. Can I avoid to use "unique_ptr" because of heap allocation?
- Maybe there is a better pattern to do this?
I also tried to do this with intense use of templates(std::is_same ... etc) but haven't got proper solution.
答案1
得分: 0
从您的代码中看,std::unordered_set<std::type_index>
似乎可以完成任务:
class Namespace {
public:
Namespace() = default;
template<typename T>
void AddTag() {
tags.insert(typeid(T));
}
template<typename T>
bool HasTag() const {
return tags.find(typeid(T)) != tags.end();
}
private:
std::unordered_set<std::type_index> tags;
};
struct TagA{};
struct TagB {};
struct TagC {};
int main ()
{
Namespace nm;
nm.AddTag<TagA>();
nm.AddTag<TagB>();
assert(nm.HasTag<TagA>());
assert(nm.HasTag<TagB>());
assert(nm.HasTag<TagC>() == false);
}
英文:
From your code, std::unordered_set<std::type_index>
seems to do the job:
class Namespace {
public:
Namespace() = default;
template<typename T>
void AddTag() {
tags.insert(typeid(T));
}
template<typename T>
bool HasTag() const {
return tags.find(typeid(T)) != tags.end();
}
private:
std::unordered_set<std::type_index> tags;
};
struct TagA{};
struct TagB {};
struct TagC {};
int main ()
{
Namespace nm;
nm.AddTag<TagA>();
nm.AddTag<TagB>();
assert(nm.HasTag<TagA>());
assert(nm.HasTag<TagB>());
assert(nm.HasTag<TagC>() == false);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论