diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2013-04-30 18:25:35 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2013-05-07 07:14:41 +0000 |
commit | 904b3d1fceee5827076758ed2a81f80cb73493ca (patch) | |
tree | 0fb9188cb3c7bb0076c98be1c4766cbf1254b508 | |
parent | 493c1e4628d2c2927ce0657497d51a1fcc37c2b3 (diff) |
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
Reviewed-on: https://gerrit.libreoffice.org/3699
Tested-by: LibreOffice gerrit bot <gerrit@libreoffice.org>
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Tested-by: Stephan Bergmann <sbergman@redhat.com>
-rw-r--r-- | cppu/qa/test_reference.cxx | 43 | ||||
-rw-r--r-- | include/com/sun/star/uno/Reference.h | 66 | ||||
-rw-r--r-- | include/com/sun/star/uno/Reference.hxx | 12 | ||||
-rw-r--r-- | sd/source/core/CustomAnimationEffect.cxx | 2 |
4 files changed, 122 insertions, 1 deletions
diff --git a/cppu/qa/test_reference.cxx b/cppu/qa/test_reference.cxx index b998238f6b39..a6e393692043 100644 --- a/cppu/qa/test_reference.cxx +++ b/cppu/qa/test_reference.cxx @@ -149,4 +149,47 @@ CPPUNIT_TEST_SUITE_REGISTRATION(Test); 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 94551a087063..27787d3ec1ef 100644 --- a/include/com/sun/star/uno/Reference.h +++ b/include/com/sun/star/uno/Reference.h @@ -160,6 +160,57 @@ enum UnoReference_SetThrow }; #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 @@ public: @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 aa39810159d3..419439ecbb9a 100644 --- a/include/com/sun/star/uno/Reference.hxx +++ b/include/com/sun/star/uno/Reference.hxx @@ -122,6 +122,18 @@ inline Reference< interface_type >::Reference( const Reference< interface_type > _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 21a098f7ee2f..827bed2af29f 100644 --- a/sd/source/core/CustomAnimationEffect.cxx +++ b/sd/source/core/CustomAnimationEffect.cxx @@ -1022,7 +1022,7 @@ Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const xAnimate->setFill( AnimationFill::HOLD ); xAnimate->setTarget( maTarget ); - return Reference< XAnimationNode >( xAnimate, UNO_QUERY_THROW ); + return xAnimate; } // -------------------------------------------------------------------- |