Reputation: 8011
I have defined operator==
as follows:
template <class State>
bool operator==(const std::shared_ptr<const State> &lhs,
const std::shared_ptr<const State> &rhs) {
return *lhs == *rhs;
}
This operator does not get instantiated (in gdb
, I cannot set the break-point on the return statement -- the line does not exist).
However, this operator should be used by std::find
called in this line:
return std::find(v.begin(), v.end(), el) != v.end();
I checked the type of v
in the above line in gdb
:
(gdb) whatis v
type = const std::vector<std::shared_ptr<Domains::IncWorst const>> &
(gdb) whatis el
type = const std::shared_ptr<Domains::IncWorst const> &
Doesn't this match my templated operator==
with State
being IncWorst
?
I implemented a toy example as follows and the example works, so I cannot understand why the real code does not.
template<class V, typename T>
bool in(const V &v, const T &el) {
return std::find(v.begin(), v.end(), el) != v.end();
}
struct MyState {
MyState(int xx) : x(xx) {}
bool operator==(const MyState &rhs) const {
return x == rhs.x;
}
int x;
};
template <class State>
bool operator==(const std::shared_ptr<const State> &lhs,
const std::shared_ptr<const State> &rhs) {
return *lhs == *rhs;
}
int main() {
std::vector<std::shared_ptr<const MyState>> v{
std::make_shared<const MyState>(5)};
auto p = std::make_shared<const MyState>(5);
std::cout << in(v, p) << std::endl; // outputs 1
return 0;
}
Upvotes: 4
Views: 126
Reputation: 157324
Your operator==
template is in the wrong namespace.
In order to be found by ADL, it must be either in the std
namespace (which would be illegal, per [namespace.std]/1) or in Domains
(per [basic.lookup.argdep]/2).
However, this is still highly dangerous, since if any template performing an equality comparison (e.g. but not limited to std::find
) is instantiated both before and after your operator==
template is declared, your whole program will be invalid per [temp.point]/8 and [basic.def.odr]/6.
If you must provide operator overload templates for std::shared_ptr
s of your types, prefer to explicitly instantiate them after the declaration of each class, such that there is less chance of a template being instantiated somewhere the class is not visible:
struct MyState {
// ...
};
template bool operator==<MyState>(
const std::shared_ptr<MyState const>&,
const std::shared_ptr<MyState const>&);
This could still be problematic if someone forward-declares MyState
somewhere else, but it's probably the best you can do.
Upvotes: 3