Ralf Holly
Ralf Holly

Reputation: 1

How to implement freestanding operators for a nested class template

I want to define freestanding operators (op==, op<, etc.) for my iterator class, but I'm struggling with the proper syntax:

template<class A>
class Container {
public:
    template<class B>
    class Iterator {
    public:
        explicit Iterator(B value) : value_(value) {};
        friend bool operator==(const Iterator& lhs, const Iterator& rhs);
    private:
        A value_;
    };
};

// Fails to compile:
template<class A>
template<class B>
bool operator==(const typename Container<A>::Iterator<B>& lhs, const typename Container<A>::template Iterator<B>& rhs) {
    return lhs.value_ == rhs.value_;
}

Container<int>::Iterator<double> it1{42.0};
Container<int>::Iterator<double> it2{42.0};
assert(it1 == it2);

Upvotes: 0

Views: 85

Answers (1)

user12002570
user12002570

Reputation: 1

First things first, the declaration for the operator== that you have(inside the class) is for a non-member nontemplate operator. So you can't implement it the way you're doing outside the class.

There are different ways of solving this.

Method 1

One way to solve this is by making the overloaded operator== a template and defining it inside the class as shown below. Note that the operator== is still a non-member.

Also note the use of typename and template keyword to tell the compiler that Iterator is a type and a template. This is also explained here.

template<typename A>
struct Container{
    template<class B>
    class Iterator {
    public:
        explicit Iterator(B value) : value_(value) {};
        //definition for a nonmember template version
        //------------------vvv-------------vvv-------->default arguments used
        template<typename U = A, typename V = B>
        //---------------------------vvvvvvvv---------->typename used here
        friend bool operator==(const typename Container<U>::template Iterator<V>& lhs, 
                               const typename Container<U>::template Iterator<V>& rhs)
        //--------------------------------------------------^^^^^^^^------------------>template used here
        {
            return lhs.value_ == rhs.value_;;
        }
    private:
        B value_;
    };
};

Container<int>::Iterator<double> it1{42.0}, it2{42.0};

int main()
{
    
    assert(it1 == it2);
}

Working demo.

Method 2

Second option is to keep the opearator== as a nontemplate as shown below:

template<typename A>
struct Container{
    template<class B>
    class Iterator {
    public:
        explicit Iterator(B value) : value_(value) {};
        
        //declaration for a nonmember nontemplate version
        //---------------------------vvvvvvvv------------------------------------------>typename used here
        friend bool operator==(const typename Container<A>::template Iterator<B>& lhs, 
                               const typename Container<A>::template Iterator<B>& rhs);
        //--------------------------------------------------^^^^^^^^------------------>template used here
        
    private:
        B value_;
    };
};
//implement the nonmember nontemplate version
bool operator==(const Container<int>::Iterator<double>&lhs, const Container<int>::Iterator<double>&rhs)
{
    return lhs.value_ == rhs.value_;
}

Container<int>::Iterator<double> it1{42.0}, it2{42.0};

int main()
{
    
    assert(it1 == it2);
}

Working demo.

Upvotes: 1

Related Questions