Boost logo

Boost :

Subject: Re: [boost] [type_traits][parameter] Inconsistent boost::is_convertible between gcc and clang
From: Michel Morin (mimomorin_at_[hidden])
Date: 2012-08-13 11:14:22


John Maddock wrote:
>> Finally, in `is_convertible_impl`, we shouldn't use `ref_type` in Line
>> 299.
>> Just using `From` is correct:
>>
>> boost::detail::is_convertible_basic_impl<From,To>::value
>>
>> With these changes, `boost::is_convertible<int, int&>` on gcc
>> returns false_type.
>
>
> It does, but it also terminally breaks C++03 compilers (not just gcc).
>
>
>> One note:
>> The above code cannot deal with `boost::is_convertible<Func, Func&>`,
>> where `Func` is a function type in a C++03 mode.
>
>
> Not only that, it also breaks for abstract types, arrays, incomplete types,
> and anything else I've forgotten.

> I've fixed the issue for GCC in C++11 mode by forwarding to
> std::is_convertible, but it remains for now in C++03 mode.

I don't think tweaking `intrinsics.hpp` is a good idea
since gcc does not implement the intrinsic yet.

The following code works well (incl. your mentioned cases)
both in C++03 and C++11 on gcc.

    template <typename From, typename To>
    struct is_convertible_basic_impl
    {
    #ifdef BOOST_NO_RVALUE_REFERENCES
        static typename ::boost::add_reference<From>::type _m_from;

        static bool const rval_to_nonconst_lval_ref_conv =
::boost::type_traits::ice_and<
            !(::boost::is_function<From>::value) // Note: an rvalue
ref to function type is an lvalue
          , !(::boost::is_reference<From>::value)
          , ::boost::is_reference<To>::value
          , !(::boost::is_const<typename
::boost::remove_reference<To>::type>::value)
>::value;

        static bool const value = ::boost::type_traits::ice_and<
            sizeof( boost::detail::checker<To>::_m_check(_m_from, 0) )
== sizeof(::boost::type_traits::yes_type)
          , !rval_to_nonconst_lval_ref_conv
>::value;
    #else
        static bool const value = sizeof(
boost::detail::checker<To>::_m_check(boost::declval<From>(), 0) )
            == sizeof(::boost::type_traits::yes_type);
    #endif
    };

    template <typename From, typename To>
    struct is_convertible_impl
    {
        BOOST_STATIC_CONSTANT(bool, value =
            (::boost::type_traits::ice_and<
                ::boost::type_traits::ice_or<
                   ::boost::detail::is_convertible_basic_impl<From,To>::value,
                   ::boost::is_void<To>::value
>::value,
                ::boost::type_traits::ice_not<
                   ::boost::type_traits::ice_or<
                      ::boost::is_array<To>::value,
                      ::boost::is_function<To>::value
>::value
>::value
>::value)
            );
    };

* The C++03 code emulates C++11's behavior.
For example, `is_convertible<Abst, Abst const&>` returns true_type
for an abstract type `Abst`.

* The code fixes the bug in the current code for function types.
For example, `is_convertible<Func, Func>` should return false_type
for a function type `Func`. But the current code returns true_type.

> Note that other compilers are similarly effected *even when using a compiler
> intrinsic*, so for example given:
>
> 1) is_convertible<int&&, int&>
> 2) is_convertible<int, int&>
>
> MSVC fails (1) even though it's using a compiler intrinsic (and no we can't
> stop using it, that breaks other stuff).
> Intel on Win32 fails both 1 & 2, again using it's __is_convertible
> intrinsic.

I just tried MSVC's `__is_convertible_to` intrinsic. It's too buggy...
Did someone make a bug report to MS?

Regards,
Michel


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