views:

76

answers:

4

I would like the following to compile, but it does not:

template <typename T>
struct Odp
{
public:
    operator*() const
    {
        return m_p;
    }

    T* operator->() const
    {
        return m_p;
    }

    T** operator&()
    {
        return &m_p;
    }

private:
        T* m_p;

};

struct Ftw : public Odp<int>
{
    bool operator==(const Ftw& rhs)
    {
        return m_p == rhs.m_p; // C2248 cannot access private member
    } 
};

Is there any way to make this work? I can't modify Odp.

A: 

The compiler is telling you that m_p is private. If you want to access m_p in the derived class you need to make it either protected or public.

nathan
... or rather use the existing public interface, which seems to provide altogether 3 different ways to get to `m_p`!
UncleBens
My answer follows what I thought was the author's intent. He specifically asked how to get what he wrote to work. To implement the operator as he has written, he will have to make the member protected or public.
nathan
+4  A: 

Odp overloads operator* to return m_p. You can invoke the operator on *this and rhs:

struct Ftw : public Odp<int>
{
    bool operator==(const Ftw& rhs) const
    {
        return **this == *rhs;
    } 
};

The operator* overload is a bit unusual, however: it should probably return *m_p instead, since operator-> returns m_p (this would result in your class having consistent pointer-like semantics). If you did this, you would then have to do the following to do the comparison:

return &**this == &*rhs; // or explicitly as:
return &this->operator*() == &rhs.operator*();

This is getting a bit messy, and it won't necessarily work if the unary & is overloaded for T (but, you really, really shouldn't do that...). You can also obtain the pointer by explicitly calling operator->, which might be preferable:

return this->operator->() == rhs.operator->();

The real question is, "what is this Odp, why are you using it, and why can you not modify it?"


On an unrelated note, your operator== should either be implemented as a const member function or, preferably, as a friend function:

bool operator==(const Ftw& rhs) const { /* ... */ }
friend bool operator==(const Ftw& lhs, const Ftw& rhs) { /* ... */ }

On another unrelated note, overloading the unary & is almost certainly a bad idea.

James McNellis
I think I would call `operator*` explicitly here. `return this->operator*() == rhs.operator*();`
Ben Voigt
@Ben: Out of curiosity, is there a particular reason you prefer the explicit `operator` syntax in this case? I generally avoid calling operators explicitly wherever possible because it seems to defeat the purpose of operator overloading (of course, given the requirements of this question, that is somewhat reasonable). I think the only time I've called an operator explicitly in production code is when I made an interesting design decision (read: royally screwed up) and made a `operator[]` template, only to realize later that it could only be called explicitly :-O.
James McNellis
I guess because the intent of the code isn't *use the object through the smart pointer*, it's *retrieve the pointer address from the smart pointer*. Maybe that reasoning is only applicable to `operator->` though.
Ben Voigt
A: 

If you can't modify Odp, you can call operator->() explicitly. It returns what you need and should get inlined.

Maciej Hehl
@Rosarch Thx for the edit, but You missed two other cases of "You" in this sentence. If capitalizing the first letter in "You" (which I do consistently for some reason, but maybe it's inappropriate for reasons I don't know of) is annoying please tell me. I'll stop.
Maciej Hehl
@Maciej Hehl Yeah, perhaps I should been more consistent. I saw the one, figured it was a typo (because capitalizing You typically means you're referring to a deity), then fixed it. Then I saw you were being consistent in your usage, and for some reason decided not to fix the rest. I guess if I'm going to go correcting others I might as well be a bit more conscientious about it.
Rosarch
A: 

Since Odp is giving the pointer out for free in its methods (even the address of it, OMG! it's like making door with many locks and then giving the keys to every thief around), you can just do

bool operator==(const Ftw& rhs)
{
    return **this == *rhs;
}

Had Odp implemented its own comparison operator, you could use it like this:

bool operator==(const Ftw& rhs)
{
    return Odp<int>::operator==(rhs) && ... other conditions ...;
}
jpalecek