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:
I also tried to do this with intense use of templates(std::is_same ... etc) but haven't got proper solution.
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);
}