Question

I prefer to write definitions for class and function templates in a separate file which is automatically included after the "public" header. However, I've come to an interesting case where it looks like I can't do that.

template <typename T>
class Outer
{
public:
    template <typename U>
    class Inner
    {
        friend bool operator ==(const Inner& lhs, const Inner& rhs);
    };
};

using Type = Outer<int>::Inner<short>;

int main()
{
    Type a;
    Type b;
    a == b;
}

Is it possible to write definition of operator== separately that will work for any T and U?

Was it helpful?

Solution 2

As Igor Tandetnik points out, your example declares a non-template friend function, which you'll have to overload for each template instantiation, which is one reason friend functions are allowed to be defined inline (so they can be generated by the template without having to be templates themselves).

If you want to define the friend function as a template, here is the closest I was able to come up with:

template <typename T>
struct Outer {
    template <typename U>
    struct Inner;
};

template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & );

template <typename T>
template <typename U>
struct Outer<T>::Inner {
    friend bool operator==<T,U>(Inner const &, Inner const &);
};

template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & ) {
    return true;
}

// I switched this out, because my gcc-4.6 doesn't
// understand "using" aliases like this yet:
typedef Outer<int>::Inner<short> Type;

int main() {
    Type a;
    Type b;
    operator==<int,short>( a, b );
}

Unfortunately, you'll notice the call site of this operator function is very awkward: operator==<int,short>( a, b ). I believe defining a function template on a nested class template like this disables (or at least interferes with) argument deduction, so you have to specify the template parameters explicitly (which means calling it as a function rather than in operator form). This is why the inline friend definition is so convenient. If you really want to define your operator=='s code separately, I'd recommend defining the friend inline to call another function template (with the proper template arguments), which you can then define out-of-line as a free function.

OTHER TIPS

For a particular specialization, yes:

template <typename T>
class Outer
{
public:
    template <typename U>
    class Inner
    {
        int x = 42;
        friend bool operator ==(const Inner& lhs, const Inner& rhs);
    };
};

using Type = Outer<int>::Inner<short>;

bool operator ==(const Type& lhs, const Type& rhs) {
    return lhs.x == rhs.x;
}

int main()
{
    Type a;
    Type b;
    a == b;
}

In your example, each specialization of the template befriends a non-template function that takes that particular specialization as parameters. You could define this function in-class (and then it will be stamped out every time the template is instantiated), or you could define it out-of-class - but then you would have to define one for every specialization you ever use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top