3

Is it possible to overload a private inner class member as a non-member? It seems to me the only way is to overload as a member.

class Foo
{
private:
    struct Bar
    {
        int a;
        char b;

        Bar& operator+=(const Bar& rhs)
        {
            a += rhs.a;
            return *this;
        }

        // Only possibility?
        inline Bar operator+(const Bar& rhs)
        {
            Bar bar;
            bar.a = this->a + rhs.a;
            bar.b = this->b;
            return bar;
        }
    };

    // Cannot do this as takes implicit reference (to Foo?).
    inline Bar operator+(Bar lhs, const Bar& rhs)
    {
        lhs += rhs;
        return lhs;
    }
};

// Cannot do this as Bar private.
inline Foo::Bar operator+(Foo::Bar lhs, const Foo::Bar& rhs)
{
    lhs += rhs;
    return lhs;
}

I guess I could just use the member overload, but I understand it's preferable to overload the + operator as a non-member, and I would like to separate the implementation.

Daniel
  • 8,179
  • 6
  • 31
  • 56
  • 3
    You could declare the operator in-class, as `friend`. – juanchopanza Aug 10 '14 at 20:51
  • `fiend` is your friend. [Working example](http://ideone.com/SotN40). Though since your `operator+` is symmetrical, there's nothing wrong with having it as a member either. You need a non-memer if you support, say, `Bar + int`, because then it would be natural to also want to support `int + Bar`, and that requires a non-member. – Igor Tandetnik Aug 10 '14 at 20:54
  • Also, for most use cases, you should take the `lhs` by `const` reference, otherwise you disable *return value optimization* and end up performing unnecessary copies (yes, I know the [SO operator overloading](http://stackoverflow.com/questions/4421706/operator-overloading) recommends that but it is sub-optimal.) – juanchopanza Aug 10 '14 at 21:03
  • But then I would need to make a copy right? I thought the idea in C++11 was to pass by value if you intend to make a copy? – Daniel Aug 10 '14 at 21:12
  • It has nothing to do with deep copies (whatever that may mean.) You disable return value optimization, which means in most cases you end up making one more copy than you would if you passed by `const` reference and copied to a local variable that you then return. I [wrote something about it here](http://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by-value/). – juanchopanza Aug 10 '14 at 21:15
  • 1
    The overload is possible by declaring the operator as friend as @juanchopanza told. The problem is that nobody else (excpet other friends and class members) have access to the inner class Foo::Bar, as it is private, so nobody else could call this operator+. What's your purpose ? Wouldn't it be simpler to declare the Bar as public ? – Christophe Aug 10 '14 at 21:17
  • 1
    The `Bar` will be used internally by other private methods, there is no reason for it to be public. – Daniel Aug 10 '14 at 21:28
  • @juanchopanza, I can't seem to implement your suggestion as a non-member (even with friend) - `Bar` being private prevents making a local copy. – Daniel Aug 10 '14 at 21:38
  • 1
    [**This is what I mean**](http://ideone.com/FPjhE3), it should work, if I understood your question correctly. – juanchopanza Aug 10 '14 at 21:43

1 Answers1

2

Doesn't look like anyone wants to claim this, I'll provide the answer for completeness. Credit goes to juanchopanza and Igor Tandetnik.

The solution is to use friend.

class Foo
{
private:
    struct Bar
    {
        int a;
        char b;

        Bar& operator+=(const Bar& rhs)
        {
            a += rhs.a;
            return *this;
        }
    };
    friend Bar operator+(Bar, const Bar&);
};

Foo::Bar operator+(Foo::Bar lhs, const Foo::Bar& rhs)
{
    lhs += rhs;
    return lhs;
}
Daniel
  • 8,179
  • 6
  • 31
  • 56