diff --git a/include/boost/detail/sp_convertible.hpp b/include/boost/detail/sp_convertible.hpp new file mode 100644 index 0000000..00463b3 --- /dev/null +++ b/include/boost/detail/sp_convertible.hpp @@ -0,0 +1,60 @@ +#ifndef BOOST_DETAIL_SP_CONVERTIBLE_HPP_INCLUDED +#define BOOST_DETAIL_SP_CONVERTIBLE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_convertible.hpp +// +// Copyright 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include + +namespace boost +{ + +namespace detail +{ + +template< class Y, class T > struct sp_convertible +{ + typedef char (&yes) [1]; + typedef char (&no) [2]; + + static yes f( T* ); + static no f( ... ); + + enum _vt { value = sizeof( f( (Y*)0 ) ) == sizeof(yes) }; +}; + +struct sp_empty +{ +}; + +template< bool > struct sp_enable_if_convertible_impl; + +template<> struct sp_enable_if_convertible_impl +{ + typedef sp_empty type; +}; + +template<> struct sp_enable_if_convertible_impl +{ +}; + +template< class Y, class T > struct sp_enable_if_convertible: public sp_enable_if_convertible_impl< sp_convertible< Y, T >::value > +{ +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SP_TYPEINFO_HPP_INCLUDED diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp index c4ec407..ace808b 100644 --- a/include/boost/intrusive_ptr.hpp +++ b/include/boost/intrusive_ptr.hpp @@ -23,8 +23,19 @@ #include #include +#if !defined( BOOST_NO_SFINAE ) +#include +#endif + #include // for std::less + +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) #include // for std::basic_ostream +#else +#include +#endif +#endif namespace boost @@ -66,9 +77,19 @@ public: #if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) - template intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.get()) + template +#if !defined( BOOST_NO_SFINAE ) + + intrusive_ptr( intrusive_ptr const & rhs, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + intrusive_ptr( intrusive_ptr const & rhs ) + +#endif + : p_( rhs.get() ) { - if(p_ != 0) intrusive_ptr_add_ref(p_); + if( p_ != 0 ) intrusive_ptr_add_ref( p_ ); } #endif @@ -246,7 +267,9 @@ template intrusive_ptr dynamic_pointer_cast(intrusive_ptr std::ostream & operator<< (std::ostream & os, intrusive_ptr const & p) { @@ -275,6 +298,8 @@ template std::basic_ostream & operator<< (std:: #endif // __GNUC__ < 3 +#endif // !defined(BOOST_NO_IOSTREAM) + } // namespace boost #ifdef BOOST_MSVC diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 9256351..7245cac 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -32,6 +32,10 @@ #include #include +#if !defined( BOOST_NO_SFINAE ) +#include +#endif + #if !defined(BOOST_SP_NO_ATOMIC_ACCESS) #include #include @@ -224,11 +228,20 @@ public: } template - shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws +#if !defined( BOOST_NO_SFINAE ) + + shared_ptr( shared_ptr const & r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + shared_ptr( shared_ptr const & r ) + +#endif + : px( r.px ), pn( r.pn ) // never throws { } - shared_ptr(detail::shared_count const & c, T * p): px(p), pn(c) // never throws + shared_ptr( detail::shared_count const & c, T * p ): px( p ), pn( c ) // never throws { } diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 4335738..aadb60a 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -61,13 +61,31 @@ public: // template - weak_ptr(weak_ptr const & r): pn(r.pn) // never throws +#if !defined( BOOST_NO_SFINAE ) + + weak_ptr( weak_ptr const & r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + weak_ptr( weak_ptr const & r ) + +#endif + : pn(r.pn) // never throws { px = r.lock().get(); } template - weak_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws +#if !defined( BOOST_NO_SFINAE ) + + weak_ptr( shared_ptr const & r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + weak_ptr( shared_ptr const & r ) + +#endif + : px( r.px ), pn( r.pn ) // never throws { } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 86d0289..3e10e73 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -46,5 +46,8 @@ import testing ; [ run sp_accept_owner_test.cpp ] [ run sp_atomic_test.cpp ] [ run make_shared_test.cpp ] + [ run sp_convertible_test.cpp ] + [ run wp_convertible_test.cpp ] + [ run ip_convertible_test.cpp ] ; } diff --git a/test/ip_convertible_test.cpp b/test/ip_convertible_test.cpp new file mode 100644 index 0000000..081f7b0 --- /dev/null +++ b/test/ip_convertible_test.cpp @@ -0,0 +1,54 @@ +#include + +// wp_convertible_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +// + +struct W +{ +}; + +void intrusive_ptr_add_ref( W* ) +{ +} + +void intrusive_ptr_release( W* ) +{ +} + +struct X: public virtual W +{ +}; + +struct Y: public virtual W +{ +}; + +struct Z: public X +{ +}; + +int f( boost::intrusive_ptr ) +{ + return 1; +} + +int f( boost::intrusive_ptr ) +{ + return 2; +} + +int main() +{ + BOOST_TEST( 1 == f( boost::intrusive_ptr() ) ); + return boost::report_errors(); +} diff --git a/test/sp_convertible_test.cpp b/test/sp_convertible_test.cpp new file mode 100644 index 0000000..165d55f --- /dev/null +++ b/test/sp_convertible_test.cpp @@ -0,0 +1,66 @@ +#include + +// sp_convertible_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +// + +class incomplete; + +struct X +{ +}; + +struct Y +{ +}; + +struct Z: public X +{ +}; + +int f( boost::shared_ptr ) +{ + return 1; +} + +int f( boost::shared_ptr ) +{ + return 2; +} + +int f( boost::shared_ptr ) +{ + return 3; +} + +int g( boost::shared_ptr ) +{ + return 4; +} + +int g( boost::shared_ptr ) +{ + return 5; +} + +int g( boost::shared_ptr ) +{ + return 6; +} + +int main() +{ + BOOST_TEST( 1 == f( boost::shared_ptr() ) ); + BOOST_TEST( 4 == g( boost::shared_ptr() ) ); + + return boost::report_errors(); +} diff --git a/test/wp_convertible_test.cpp b/test/wp_convertible_test.cpp new file mode 100644 index 0000000..cceacda --- /dev/null +++ b/test/wp_convertible_test.cpp @@ -0,0 +1,68 @@ +#include + +// wp_convertible_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +// + +class incomplete; + +struct X +{ +}; + +struct Y +{ +}; + +struct Z: public X +{ +}; + +int f( boost::weak_ptr ) +{ + return 1; +} + +int f( boost::weak_ptr ) +{ + return 2; +} + +int f( boost::weak_ptr ) +{ + return 3; +} + +int g( boost::weak_ptr ) +{ + return 4; +} + +int g( boost::weak_ptr ) +{ + return 5; +} + +int g( boost::weak_ptr ) +{ + return 6; +} + +int main() +{ + BOOST_TEST( 1 == f( boost::weak_ptr() ) ); + BOOST_TEST( 1 == f( boost::shared_ptr() ) ); + BOOST_TEST( 4 == g( boost::weak_ptr() ) ); + BOOST_TEST( 4 == g( boost::shared_ptr() ) ); + + return boost::report_errors(); +}