hob-B1T
hob-B1T

Reputation: 73

Problems overloading operator== of template sub class

I've problems overloading operator==, different compiler errors using VC++(2015) and g++ 5.4.0 (--std==c++14). Here's the code (this is just an extract of a more complex situation in my real code base):

#include <vector>

template<typename T>
struct A {
    struct B {
        std::vector<T> _elements;

        // Internal cmp op.
        bool operator==(const B &other) {
            return _elements == other._elements;
        }
    };

    std::vector<B> _entries;
};

// External cmp op.
template<typename T>
inline bool operator==(typename const A<T>::B &l, typename const A<T>::B & r) {
    return l._elements == r._elements;
}

int main() {
    A<int>::B b0, b1;

    b0.operator==(b1);                            // a
    operator==<int>(b0, b1);                      // b
    b0 == b1;                                     // c

    std::vector<A<int>::B> v0, v1;

    std::equal(v0.begin(), v0.end(), v1.begin()); // d
    v0 == v1;                                     // e

    return 0;
}

I do not add the error messages, because I have the german version of VC++ and the g++ errors span over many lines.

VC++ gives an error on (e). I don't understand why, because vector<>::operator== seems to call std::equal internally and (d) compiles fine. Why does this fail?

g++ fails to accept my external operator==(), so totally fails to compile this short code. I have no idea how to write an external operator==() for A<T>::B that works with both compilers.

I haven't tried clang yet.

Many thanks.

Upvotes: 3

Views: 91

Answers (1)

TemplateRex
TemplateRex

Reputation: 70546

There were two errors in your program:

    // Internal cmp op.
    bool operator==(const B &other) const {
                                    ///// <- here
        return _elements == other._elements;
    }

should be a const member and the keyword const cannot appear just behind the typename:

// External cmp op.
template<typename T>
inline bool operator==(typename A<T>::B const& lhs, typename A<T>::B const& rhs)
                                        ///// <-         here    ->  ////
{
    return lhs._elements == rhs._elements;
}

Live Example

Note that the placement of const is usually fairly liberal in C++, e.g. you can write both const typename A<T>::B & lhs and typename A<T>::B const& lhs, but the form you chose, typename const A<T>::B & lhs is not allowed.

Also note that you want to write either a member operator== or a non-member operator==, but never both. In your case, because T is not deducible in typename A<T>::B, you have to write the ugly operator==<int>(b0, b1) to select the non-member.

I would remove the non-member template operator== and add to your class template A<T> a non-member

bool operator==(const A &other) const {
    return _entries == other._entries;    
}

so that you can also compare objects of A<int>. Note that this will call the standard library operator== for std::vector which in turn will call your operator== for B.

Upvotes: 3

Related Questions