2

Is it possible to override the -> operator in template class and return something by reference?

I saw this post: Overloading member access operators ->, .*

And there is an example of overriding -> and return by reference, but I can't get this to work with templates. Here's a small example of what I'm trying to achieve:

#include <iostream>

using namespace std;

class A
{
public:
    void do_something()
    {
        cout << "Hey there";
    }
};

template<class T>
class Ref
{
public:
    Ref(T* ptr)
    {
        objPtr = ptr;
    }

    // this is another alternative, but I don't want to write Get() every time I want to access the object
    T& get() { return *objPtr; }

    template <class T>
    Ref<T>& operator->() const { return *objPtr; }

    // doesn't work either
    //T& operator->() const { return *objPtr; }

    // this works as expected, but I really MUST return by reference
    //T* operator->() const { return objPtr; } 

private:
    T* objPtr;
};

int main()
{
    A myObj;
    Ref<A> ref(&myObj);

    // error C2675: unary '->': 'Ref<A>' does not define this operator or a conversion to a type acceptable to the predefined operator
    ref->do_something(); 

    return 0;
}

How can this be done?

Gregor Sattel
  • 352
  • 3
  • 12
  • Why not return a pointer? `const T* operator->() const { return objPtr; }` and `T* operator->() { return objPtr; }` – Ted Lyngmo Aug 24 '21 at 16:03
  • Why do you want to return a reference? The example you link to returns a reference to an object that also implements `operator->` and returns a pointer. The point being made was that you still got a pointer. – Drew Dormann Aug 24 '21 at 16:05

1 Answers1

4

If you return a reference, you can't use it in ref->do_something(); which requires a pointer. You'd have to use this cumbersome method:

ref.operator->().do_something(); 

Instead return a pointer - and make it a T* (or const T*), not a Ref<T>*.

Example:

#include <iostream>

class A {
public:
    void do_something() {
        std::cout << "Hey there\n";
    }
};

template<class T>
class Ref {
public:
    Ref(T& ptr) : objPtr(&ptr) {} // taking a T& but storing a pointer

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

private:
    T* objPtr;
};

int main() {
    A myObj;
    Ref<A> ref(myObj);

    ref->do_something(); 
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Or, instead of storing a pointer, store a reference and convert it to a pointer when needed. `template class Ref { public: Ref(T& obj) : objRef(obj) {} const T* operator->() const { return &objRef; } T* operator->() { return &obj; } private: T& objRef; };` But this `Ref` class seems pretty moot when [`std::reference_wrapper`](https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper) exists. – Remy Lebeau Aug 24 '21 at 16:23
  • @RemyLebeau Yeah, storing a reference is an option but makes copying/moving a pain so I prefer a pointer in this case. – Ted Lyngmo Aug 24 '21 at 16:32
  • That is exactly what `std::reference_wrapper` is meant for - a storable, copyable/movable, reassignable reference. – Remy Lebeau Aug 24 '21 at 16:35
  • @RemyLebeau Yepp, I'm aware of that. Perhaps I should have added a note about it in the answer but I got the impression OP was experimenting to learn how to do it – Ted Lyngmo Aug 24 '21 at 16:40