Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't auto_ptr support op->*()

auto_ptr (shared_ptr as well) try to make their use as transparent as possible; that is, ideally, you should not be able to tell a difference whether you're using an auto_ptr or a real pointer to an object. Consider:

class MyClass
{
public:
    void foo() {  }
};

MyClass* p = new MyClass;
auto_ptr<MyClass> ap(new MyClassp);

p->foo();       // No notational difference in using real
ap->foo();      // pointers and auto_ptrs

When you try to invoke a member function through a pointer-to-member, there is a difference, as auto_ptr obviously doesn't implement op->*():

void (MyClass::*memfun)() = &MyClass::foo;

(p->*memfun)();         // OK
(ap->*memfun)();        // Error op->*() missing
(ap.get()->*memfun)();  // OK

Why is there no support for op->*() in auto_ptr and how would one implement it (I've experimented for some time, but ultimately gave up).

like image 490
Ralf Holly Avatar asked Jul 17 '10 17:07

Ralf Holly


2 Answers

As Luther points out its non-trivial to implement - but it is possible.

You have to

  1. use templates so the type of the arguments to operator->* can be deduced
  2. take care of possible qualifiers and multiple function arities using overloads
  3. for member function pointers return a callabe object that is:
    • bound to the instance the smart pointer points to
    • implements an operator() with a signature equivalent to the member function

Ignoring qualifiers for the momement, here is how it could basically look (using C++0x to avoid manual repitition):

// pointer to data member:

template<class T, class D>
D& operator->*(std::auto_ptr<T>& p, D T::*mp) {
    return (*p).*mp;
}

// pointer to member function:

template<class T, class R, class... Args> struct Callable {
    typedef R (T::*MFP)(Args...);
    MFP mfp;
    T& instance;

    Callable(T t, MFP mfp) : instance(t), mfp(mfp) {}

    R operator()(Args... a) {
        return (instance.*mfp)(a...);
    }
};

template<class T, class R, class... Args>
Callable<T, R, Args...>
operator->*(std::auto_ptr<T>& p, R (T::*mfp)(Args...)) {
    return Callable<T, R, Args...>(*p, mfp);
}

But in the end, why bother when we could just use functors that bind member pointers in the first place.

While i can't be sure about it, if you combine the knowledge that

  • the implementation is non-trivial
  • there is an easy alternative that works just as well ((*p).*m)

... its probably usually not implemented due to a bad ratio of the work-needed to the gains resulting from this feature.

like image 186
Georg Fritzsche Avatar answered Sep 25 '22 01:09

Georg Fritzsche


implementing ->* would require to solve the perfect forwarding problem:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm

operator->* would have to return a callable object with the same parameter list as the pointer-to-member object, correctly handling const-,volatileness and reference types. And then it would have to employ special magic powers to handle default parameters. This is difficult, error prone, unsolvable and eats too much compile time and since pointer-to-members are a comparably marginally popular feature of C++, they are generally left out of smart pointer implementations.

like image 25
Nordic Mainframe Avatar answered Sep 22 '22 01:09

Nordic Mainframe