There is no common base-type between those containers. That's just not the way the STL library works, it is based on templates and generic programming principles.
So, if you want to implement the function once for all containers, you would have to make it a template. Here is a basic form:
template <typename TagContainer>
bool Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
But this has the problem that you could technically pass anything to this function that isn't actually a container of SharedTag
, so, to solve this issue, you could use a trick called Sfinae to enforce that rule:
template <typename TagContainer>
typename std::enable_if< std::is_same< SharedTag, typename TagContainer::value_type >::value,
bool >::type Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
Which kind of ugly, but it works.
There is still one problem though. I suspect that your Tag
class is a normal non-template class, which means that you are probably implementing it in a cpp file, but templates need to be implemented in the header file (because function templates need to have their implementation visible to the compiler to generate a new concrete version of it for each type that you call it with).
One way to avoid this problem is to provide a number of overloaded non-template functions for each container you want to support, and then, under-the-hood, you call a local function template, and in this case, you don't need the sfinae trick to constrain it, since it is already limited to the set of overloads that you provided. Something like this:
template <typename TagContainer>
bool Tag::isIn_impl(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
bool Tag::isIn(const std::list<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::vector<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::set<SharedTag>& lst) {
return isIn_impl(lst);
};
Note that the isIn_impl
is a member function template that should be declared in the header file, in the private section of the class, and can safely be defined in the cpp file, because that cpp file is the only place where that function template is called from.
The obvious issue with that solution is that you have to manually provide every overload that you want to support, which means that it isn't very "scalable" in the future, but in real-life, there probably aren't that many containers that you'd want to support. If you want the full generality, you really have to use the template approach (unless you want to do type-erasure on the container... but that's a bit beyond the scope of what I'm willing to explain here).