I want to write a function that accepts a collection of type T
, say std::vector<T>
, but that does two different things depending on T
. For example, if T
is ==
comparable, then use a == b
, else if T
has a .value
element, use that (a.value == b.value
).
My first attempt was to use an overloaded function, but that fails if I pass in a derived class (subclass) of T
.
Suppose, for example, I want to create an Exists
method. (I know this can be implemented using std::find_if
; it is an example only.) The following fails to compile:
using namespace std;
struct Base {
Base(string s) : value(std::move(s)) {}
string value;
};
struct Derived : public Base {
Derived(string s) : Base(std::move(s)) {}
};
bool Exists(const vector<string>& collection, const string& item) {
for (const auto& x : collection)
if (x == item)
return true;
return false;
}
bool Exists(const vector<Base>& collection, const Base& item) {
for (const auto& x : collection)
if (x.value == item.value)
return true;
return false;
}
This works fine for exact matches, such as:
Exists(vector<string>{"a", "b", "c"}, "b");
Exists(vector<Base>{{"a"}, {"b"}, {"c"}}, Base{"b"});
But it fails for derived classes:
Exists(vector<Derived>{{"a"}, {"b"}, {"c"}}, Derived{"b"})
The error is:
foo.cc:35:13: error: no matching function for call to 'Exists'
foo.cc:23:6: note: candidate function not viable: no known conversion from 'vector<Derived>' to 'const vector<Base>' for
1st argument
How can I solve this? I am interested in multiple answers, since each solution probably has pros and cons.