
on Tue Jan 06 2009, Howard Hinnant <hinnant-AT-twcny.rr.com> wrote:
On Jan 6, 2009, at 10:45 AM, David Abrahams wrote:
on Mon Jan 05 2009, Howard Hinnant <hinnant-AT-twcny.rr.com> wrote:
I'm continuing to refine a boost::unique_ptr emulation and testsuite.
Howard, can you put this in the sandbox? I know there are a number of us who would like very much to collaborate on it.
I will make it available as soon as I can at http://home.roadrunner.com/~hinnant/unique_ptr03.html
There will be plenty of room for collaboration. Indeed I feel like that is already happening with the discussion in this thread.
For optimal collaboration you need source control. That's why I suggest the sandbox. That's probably the only way I'd be able to afford to work on it.
One thing I've just uncovered is that I'm hitting a brick wall with is_convertible and move-only deleters used within the unique_ptr move constructor. The problem is that boost::is_convertible<From, To> assumes From is an lvalue.
Sorry to be nitpicky, but that's not making sense to me. IIUC the terms lvalue and rvalue can only apply to expressions, not types. Are you saying that From has to be a reference type? Surely not.
I'm saying that if you construct a To from a From, you /may/ get different answers (on whether the construction works or not) depending upon if you consider From an lvalue or rvalue:
From f; To t1 = f; // one answer To t2 = From(); // potentially a different answer
Right.
More specifically, if To and From are the same move-only type (say unique_ptr<int>), then you /do/ get a different answer.
That being said, the vast majority of the is_convertible use cases simply don't care if the source is considered an lvalue or rvalue. E.g.:
is_convertible<T*, U*>::value
(same answer either way with pointers)
is_convertible<Deleter, Deleter> gets instantiated and it is all over.
Specifically, how?
The boost::is_convertible implementation requires access to a Deleter copy constructor. My modifications to the boost::is_convertible implementation treat the From as an rvalue and will attempt the "auto_ptr solution" for making a copy from an rvalue when From is an emulated move-only type (avoiding the Deleter copy constructor, and using the conversion to the rv<Deleter> instead).
I've modified my copy of is_convertible (without really knowing what I'm doing) like so:
Index: is_convertible.hpp =================================================================== --- is_convertible.hpp (revision 50433) +++ is_convertible.hpp (working copy) @@ -119,6 +119,8 @@ struct any_conversion { template <typename T> any_conversion(const volatile T&); + template <typename T> any_conversion(volatile T&); + template <typename T> any_conversion(const T&); template <typename T> any_conversion(T&); };
@@ -131,8 +133,8 @@ template <typename From, typename To> struct is_convertible_basic_impl { - static From _m_from; - static bool const value = sizeof( detail::checker<To>::_m_check(_m_from, 0) ) + static From _m_from(); + static bool const value = sizeof( detail::checker<To>::_m_check(_m_from(), 0) ) == sizeof(::boost::type_traits::yes_type); };
Note the From above is not the same as the one below at least in the current code.
I ran svn update on the boost-trunk before creating this diff.
You miss my point. I'm just pointing out that in the current code, the
From above is always a reference type and the From below is not necessarily a reference type.
@@ -291,7 +293,8 @@ template <typename From, typename To> struct is_convertible_impl { - typedef typename add_reference<From>::type ref_type; +// typedef typename add_reference<From>::type ref_type; + typedef From ref_type; BOOST_STATIC_CONSTANT(bool, value = (::boost::type_traits::ice_and< ::boost::type_traits::ice_or<
So it used to pass an lvalue of type _m_from, and after your change it passes an rvalue. Of course, your change now assumes that From can be returned from a function. I think you'll have a problem if you try this with From being a noncopyable non-movable type.
Did you overlook this remark completely?
This hits just the part targeting gcc.
(and old Borland compilers).
The intent is that in boost::is_convertible<From, To> From is now considered an rvalue (unless From is a (lvalue) reference type). This makes my test case happy. I can now move construct a unique_ptr with a move-only deleter.
Fwiw, this definition of is_convertible is consistent with std::is_convertible in N2800:
I was just going to ask that.
To emulate the N2800 definition in C++03 one must treat void, array and function types specially in the implementation (arrays and functions can't be returned from functions and void can't be a function parameter). Even so, a C++03 library emulation will get noncopyable non-movable types wrong (as will the current boost::is_convertible).
I'm claiming that your emulation gives a compile-time error in that case. -- Dave Abrahams BoostPro Computing http://www.boostpro.com