Bug 1189231 - Impl operator->* to nsAutoPtr. r=nfroyd
authorJames Cheng <jacheng@mozilla.com>
Thu, 30 Jul 2015 21:02:00 -0400
changeset 287815 312dce5d5216521b8b14a47c7cc5cabaafbd90bf
parent 287763 74a44d30db0966cfd9fae78da300c1953c1016ed
child 287816 5cadf71b19b2de36440711aa22342c1952d7ffa6
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd
bugs1189231
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1189231 - Impl operator->* to nsAutoPtr. r=nfroyd
xpcom/base/nsAutoPtr.h
xpcom/tests/TestAutoPtr.cpp
--- a/xpcom/base/nsAutoPtr.h
+++ b/xpcom/base/nsAutoPtr.h
@@ -192,29 +192,42 @@ public:
   T*
   operator->() const
   {
     NS_PRECONDITION(mRawPtr != 0,
                     "You can't dereference a NULL nsAutoPtr with operator->().");
     return get();
   }
 
-  // This operator is needed for gcc <= 4.0.* and for Sun Studio; it
-  // causes internal compiler errors for some MSVC versions.  (It's not
-  // clear to me whether it should be needed.)
-#ifndef _MSC_VER
-  template <class U, class V>
-  U&
-  operator->*(U V::* aMember)
+  template <typename R, typename... Args>
+  class Proxy
+  {
+    typedef R (T::*member_function)(Args...);
+    T* mRawPtr;
+    member_function mFunction;
+  public:
+    Proxy(T* aRawPtr, member_function aFunction)
+      : mRawPtr(aRawPtr),
+        mFunction(aFunction)
+    {
+    }
+    template<typename... ActualArgs>
+    R operator()(ActualArgs&&... aArgs)
+    {
+      return ((*mRawPtr).*mFunction)(mozilla::Forward<ActualArgs>(aArgs)...);
+    }
+  };
+
+  template <typename R, typename C, typename... Args>
+  Proxy<R, Args...> operator->*(R (C::*aFptr)(Args...)) const
   {
     NS_PRECONDITION(mRawPtr != 0,
                     "You can't dereference a NULL nsAutoPtr with operator->*().");
-    return get()->*aMember;
+    return Proxy<R, Args...>(get(), aFptr);
   }
-#endif
 
   nsAutoPtr<T>*
   get_address()
   // This is not intended to be used by clients.  See |address_of|
   // below.
   {
     return this;
   }
--- a/xpcom/tests/TestAutoPtr.cpp
+++ b/xpcom/tests/TestAutoPtr.cpp
@@ -8,16 +8,22 @@
 #include <stdio.h>
 #include "nscore.h"
 #include "mozilla/Attributes.h"
 
 class TestObjectBaseA {
     public:
         // Virtual dtor for deleting through base class pointer
         virtual ~TestObjectBaseA() { }
+        void MemberFunction( int, int*, int& )
+        {
+          printf("member function is invoked.\n");
+        }
+        virtual void VirtualMemberFunction(int, int*, int&) { };
+        virtual void VirtualConstMemberFunction(int, int*, int&) const { };
         int fooA;
 };
 
 class TestObjectBaseB {
     public:
         // Virtual dtor for deleting through base class pointer
         virtual ~TestObjectBaseB() { }
         int fooB;
@@ -32,16 +38,25 @@ class TestObject : public TestObjectBase
         }
 
         // Virtual dtor for deleting through base class pointer
         virtual ~TestObject()
         {
             printf("  Destroying TestObject %p.\n",
                    static_cast<void*>(this));
         }
+
+        virtual void VirtualMemberFunction(int, int*, int&) override
+        {
+          printf("override virtual member function is invoked.\n");
+        }
+        virtual void VirtualConstMemberFunction(int, int*, int&) const override
+        {
+          printf("override virtual const member function is invoked.\n");
+        }
 };
 
 class TestRefObjectBaseA {
     public:
         int fooA;
         // Must return |nsrefcnt| to keep |nsDerivedSafe| happy.
         virtual nsrefcnt AddRef() = 0;
         virtual nsrefcnt Release() = 0;
@@ -534,10 +549,24 @@ int main()
         const nsRefPtr<TestRefObject> pobj = new TestRefObject();
         printf("Should do something with one |TestRefObject|:\n");
         DoSomethingWithTestRefObjectBaseB(pobj);
         printf("Should do something with one |TestRefObject|:\n");
         DoSomethingWithConstTestRefObjectBaseB(pobj);
         printf("Should Release and destroy one |TestRefObject|:\n");
     }
 
+    {
+        int test = 1;
+        void (TestObjectBaseA::*fPtr)( int, int*, int& ) = &TestObjectBaseA::MemberFunction;
+        void (TestObjectBaseA::*fVPtr)( int, int*, int& ) = &TestObjectBaseA::VirtualMemberFunction;
+        void (TestObjectBaseA::*fVCPtr)( int, int*, int& ) const = &TestObjectBaseA::VirtualConstMemberFunction;
+        printf("Should create one |TestObject|:\n");
+        nsAutoPtr<TestObjectBaseA> pobj(new TestObject());
+        printf("Should do something with operator->*:\n");
+        (pobj->*fPtr)(test, &test, test);
+        (pobj->*fVPtr)(test, &test, test);
+        (pobj->*fVCPtr)(test, &test, test);
+        printf("Should destroy one |TestObject|:\n");
+    }
+
     return 0;
 }