Boost logo

Boost :

Subject: Re: [boost] is_convertible problems associated with move-only types
From: Howard Hinnant (hinnant_at_[hidden])
Date: 2009-01-06 13:12:27


On Jan 6, 2009, at 12:37 PM, David Abrahams wrote:

>
> 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.

Understood. I'm a boost sandbox newbie and am juggling too many
things today to even learn how to get boost sandbox access. For now I
have a better, but still incomplete, tests and source up at:

    http://home.roadrunner.com/~hinnant/unique_ptr03.html

The tests are hierarchical, organized according to N2800's
[unique.ptr]. One can:

$ export CC=g++
$ export BOOST_INCLUDE="-I/<path-to>/boost-trunk"
$ export SOURCE_INCLUDE="-I/<path-to>/unique_ptr"

And then cd into any directory under unique.ptr and:

$ ./test

6 of the tests currently fail for me. 2 of them are fixed by changing
boost::is_convertible's From to an rvalue. The other 4 I currently
don't know how to fix. They involve unique_ptr's converting ctor. My
current fear is that our generalized move library won't handle this,
but I hope I'm wrong.

$ ./test
...
failed 6 tests in /Users/hinnant/Development/unique_ptr/unique.ptr/
unique.ptr.single/unique.ptr.single.ctor
...
failed 6 tests in /Users/hinnant/Development/unique_ptr/unique.ptr/
unique.ptr.single
failed 6 tests in /Users/hinnant/Development/unique_ptr/unique.ptr

>>>> 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.

I know that. I did that on purpose. I'm still missing your point.

>>>> @@ -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?

No, I commented on it below.

>
>
>>>> 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.

I'm claiming that so does boost:

Compiled against revision 50433:

$ cat test.cpp
#include <boost/type_traits.hpp>

class non_copyable_non_movable
{
     int data_;

     non_copyable_non_movable(const non_copyable_non_movable&);
     non_copyable_non_movable& operator=(const
non_copyable_non_movable&);

public:

     non_copyable_non_movable() : data_(0) {}
};

int main()
{
     bool b = boost::is_convertible<non_copyable_non_movable,
                                    non_copyable_non_movable>::value;
}

$ g++ g++ -I/Users/hinnant/Development/boost-dev/boost-trunk test.cpp
/Users/hinnant/Development/boost-dev/boost-trunk/boost/type_traits/
is_convertible.hpp: In instantiation of
‘boost::detail::is_convertible_basic_impl<non_copyable_non_movable&,
non_copyable_non_movable>’:
/Users/hinnant/Development/boost-dev/boost-trunk/boost/type_traits/
is_convertible.hpp:295: instantiated from
‘boost::detail::is_convertible_impl<non_copyable_non_movable,
non_copyable_non_movable>’
/Users/hinnant/Development/boost-dev/boost-trunk/boost/type_traits/
is_convertible.hpp:372: instantiated from
‘boost::detail::is_convertible_impl_dispatch<non_copyable_non_movable,
non_copyable_non_movable>’
/Users/hinnant/Development/boost-dev/boost-trunk/boost/type_traits/
is_convertible.hpp:418: instantiated from
‘boost::is_convertible<non_copyable_non_movable,
non_copyable_non_movable>’
test.cpp:18: instantiated from here
test.cpp:7: error:
‘non_copyable_non_movable::non_copyable_non_movable(const
non_copyable_non_movable&)’ is private
/Users/hinnant/Development/boost-dev/boost-trunk/boost/type_traits/
is_convertible.hpp:136: error: within this context
/Users/hinnant/Development/boost-dev/boost-trunk/boost/type_traits/
is_convertible.hpp:136: error: initializing argument 1 of ‘static
boost::type_traits::yes_type boost::detail::checker<T>::_m_check(T,
int) [with T = non_copyable_non_movable]’

I know of no way to fix this in C++03. I strongly suspect it will
take C++0X std::Convertible to get this one right (or compiler support
such as __is_convertible(T,U)).

Correct handling of noncopyable nonmovable types has no bearing on
this discussion. We are *not* going to get it right. However we
*can* get noncopyable movable types right if we choose to. Currently
boost handles only copyable types.

-Howard


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk