[PATCH] Up-cast conversion constructor for css::uno::Reference

Stephan Bergmann (via Code Review) gerrit at gerrit.libreoffice.org
Tue Apr 30 09:29:08 PDT 2013


Hi,

I have submitted a patch for review:

    https://gerrit.libreoffice.org/3699

To pull it, you can do:

    git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/99/3699/1

Up-cast conversion constructor for css::uno::Reference

Based on a previous patch by Noel Grandin,
<https://gerrit.libreoffice.org/#/c/3613/>, and borrowing from
boost::is_base_and_derived (see comment in include/com/sun/star/uno/Reference.h)
to avoid including Boost headers in URE headers.

Change-Id: Iade5af144dd73ef03bd7d96000134c7a66a5e591
---
M cppu/qa/test_reference.cxx
M include/com/sun/star/uno/Reference.h
M include/com/sun/star/uno/Reference.hxx
M sd/source/core/CustomAnimationEffect.cxx
4 files changed, 122 insertions(+), 1 deletion(-)



diff --git a/cppu/qa/test_reference.cxx b/cppu/qa/test_reference.cxx
index b998238..a6e3936 100644
--- a/cppu/qa/test_reference.cxx
+++ b/cppu/qa/test_reference.cxx
@@ -149,4 +149,47 @@
 
 CPPUNIT_PLUGIN_IMPLEMENT();
 
+// Check that the up-casting Reference conversion constructor catches the
+// intended cases:
+
+namespace {
+
+struct Base1: public css::uno::XInterface { virtual ~Base1() {} };
+struct Base2: public Base1 { virtual ~Base2() {} };
+struct Base3: public Base1 { virtual ~Base3() {} };
+struct Derived: public Base2, public Base3 { virtual ~Derived() {} };
+
+}
+
+// The special case using the conversion operator instead:
+css::uno::Reference< css::uno::XInterface > testUpcast1(
+    css::uno::Reference< Derived > const & ref)
+{ return ref; }
+
+// The normal up-cast case:
+css::uno::Reference< Base1 > testUpcast2(
+    css::uno::Reference< Base2 > const & ref)
+{ return ref; }
+
+// Commenting this in should cause a compiler error due to an ambiguous up-cast:
+/*
+css::uno::Reference< Base1 > testFailingUpcast3(
+    css::uno::Reference< Derived > const & ref)
+{ return ref; }
+*/
+
+// Commenting this in should cause a compiler error due to a down-cast:
+/*
+css::uno::Reference< Base2 > testFailingUpcast4(
+    css::uno::Reference< Base1 > const & ref)
+{ return ref; }
+*/
+
+// Commenting this in should cause a compiler error due to a down-cast:
+/*
+css::uno::Reference< Base1 > testFailingUpcast5(
+    css::uno::Reference< css::uno::XInterface > const & ref)
+{ return ref; }
+*/
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/com/sun/star/uno/Reference.h b/include/com/sun/star/uno/Reference.h
index 94551a0..27787d3 100644
--- a/include/com/sun/star/uno/Reference.h
+++ b/include/com/sun/star/uno/Reference.h
@@ -160,6 +160,57 @@
 };
 #endif
 
+/// @cond INTERNAL
+namespace detail {
+
+// A mechanism to enable up-casts, used by the Reference conversion constructor,
+// but at the same time disable up-casts to XInterface, so that the conversion
+// operator for that special case is used in an expression like
+// Reference< XInterface >(x); heavily borrowed from boost::is_base_and_derived
+// (which manages to avoid compilation problems with ambiguous bases and cites
+// comp.lang.c++.moderated mail <http://groups.google.com/groups?
+// selm=df893da6.0301280859.522081f7%40posting.google.com> "SuperSubclass
+// (is_base_and_derived) complete implementation!" by Rani Sharoni and cites
+// Aleksey Gurtovoy for the workaround for MSVC), to avoid including Boost
+// headers in URE headers (could ultimately be based on C++11 std::is_base_of):
+
+template< typename T1, typename T2 > struct UpCast {
+private:
+    template< bool, typename U1, typename > struct C
+    { typedef U1 t; };
+
+    template< typename U1, typename U2 > struct C< false, U1, U2 >
+    { typedef U2 t; };
+
+    struct S { char c[2]; };
+
+#if defined _MSC_VER
+    static char f(T2 *, long);
+    static S f(T1 * const &, int);
+#else
+    template< typename U > static char f(T2 *, U);
+    static S f(T1 *, int);
+#endif
+
+    struct H {
+        H(); // avoid C2514 "class has no constructors" from MSVC 2008
+#if defined _MSC_VER
+        operator T1 * const & () const;
+#else
+        operator T1 * () const;
+#endif
+        operator T2 * ();
+    };
+
+public:
+    typedef typename C< sizeof (f(H(), 0)) == 1, void *, void >::t t;
+};
+
+template< typename T2 > struct UpCast< XInterface, T2 > {};
+
+}
+/// @endcond
+
 /** Template reference class for interface type derived from BaseReference.
     A special constructor given the UNO_QUERY identifier queries interfaces
     for reference type.
@@ -248,6 +299,21 @@
         @param rRef another reference
     */
     inline Reference( const Reference< interface_type > & rRef ) SAL_THROW(());
+
+    /** Up-casting conversion constructor: Copies interface reference.
+
+        Does not work for up-casts to ambiguous bases.  For the special case of
+        up-casting to Reference< XInterface >, see the corresponding conversion
+        operator.
+
+        @param rRef another reference
+    */
+    template< class derived_type >
+    inline Reference(
+        const Reference< derived_type > & rRef,
+        typename detail::UpCast< interface_type, derived_type >::t = 0 )
+        SAL_THROW(());
+
     /** Constructor: Sets given interface pointer.
 
         @param pInterface an interface pointer
diff --git a/include/com/sun/star/uno/Reference.hxx b/include/com/sun/star/uno/Reference.hxx
index aa39810..419439e 100644
--- a/include/com/sun/star/uno/Reference.hxx
+++ b/include/com/sun/star/uno/Reference.hxx
@@ -122,6 +122,18 @@
         _pInterface->acquire();
 }
 //__________________________________________________________________________________________________
+template< class interface_type > template< class derived_type >
+inline Reference< interface_type >::Reference(
+    const Reference< derived_type > & rRef,
+    typename detail::UpCast< interface_type, derived_type >::t )
+    SAL_THROW(())
+{
+    interface_type * p = rRef.get();
+    _pInterface = p;
+    if (_pInterface)
+        _pInterface->acquire();
+}
+//__________________________________________________________________________________________________
 template< class interface_type >
 inline Reference< interface_type >::Reference( interface_type * pInterface ) SAL_THROW(())
 {
diff --git a/sd/source/core/CustomAnimationEffect.cxx b/sd/source/core/CustomAnimationEffect.cxx
index 21a098f..827bed2 100644
--- a/sd/source/core/CustomAnimationEffect.cxx
+++ b/sd/source/core/CustomAnimationEffect.cxx
@@ -1022,7 +1022,7 @@
     xAnimate->setFill( AnimationFill::HOLD );
     xAnimate->setTarget( maTarget );
 
-    return Reference< XAnimationNode >( xAnimate, UNO_QUERY_THROW );
+    return xAnimate;
 }
 
 // --------------------------------------------------------------------

-- 
To view, visit https://gerrit.libreoffice.org/3699
To unsubscribe, visit https://gerrit.libreoffice.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iade5af144dd73ef03bd7d96000134c7a66a5e591
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: master
Gerrit-Owner: Stephan Bergmann <sbergman at redhat.com>



More information about the LibreOffice mailing list