简体   繁体   中英

Why does my templated operator== not get used?

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;
}

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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM