Boost logo

Boost Users :

Subject: Re: [Boost-users] Regression in Boost.Variant with gcc6.3 in C++03 mode
From: d25fe0be_at_[hidden]
Date: 2017-06-27 15:46:24


> On 27 Jun 2017, at 20:09, dariomt--- via Boost-users <boost-users_at_[hidden]> wrote:
>
> #include <boost/variant.hpp>
> class A {};
> class B : private A {};
> typedef boost::variant<A, B> variant_t;
> int main()
> {
> B b;
> variant_t v (b);
> }
>

In `boost/type_traits/is_convertible.hpp`:

```
   123 struct any_conversion
   124 {
   125 template <typename T> any_conversion(const volatile T&);
   126 template <typename T> any_conversion(const T&);
   127 template <typename T> any_conversion(volatile T&);
   128 template <typename T> any_conversion(T&);
   129 };
   130
   131 template <typename T> struct checker
   132 {
   133 static boost::type_traits::no_type _m_check(any_conversion ...);
   134 static boost::type_traits::yes_type _m_check(T, int);
   135 };
```

And according to [https://stackoverflow.com/questions/30004771/why-is-a-malformed-function-used-instead-of-an-implicit-conversion], the standard conversion sequence takes precedence of the user-defined conversion (`any_conversion`), hence `checker<A>::_m_check(B(), 0)` results in a hard error.

So I suspect this is a bug in 'type_traits' library, but I'm not sure. Hopefully somebody else can confirm. (I'm sorry but I don't know to whom should I CC this post.)

An easy workaround would be specializing `boost::is_convertible` for your classes:

```
namespace boost {
template <> struct is_convertible<B&, A> : boost::false_type {};
template <> struct is_convertible<const B&, A> : boost::false_type {};
}

```

I don't know why clang accepts your code though. Perhaps `boost::is_convertible` is conditionally compiled to some different implementations in Clang.

------

A reduced repo of the hard error in `boost::is_convertible` is:

```
struct any_conversion
{
        template <typename T> any_conversion(const volatile T&);
        template <typename T> any_conversion(const T&);
        template <typename T> any_conversion(volatile T&);
        template <typename T> any_conversion(T&);
};

typedef char (&yes_type)[2];
typedef char (&no_type)[1];

class A {};
class B : private A {};

static no_type _m_check(any_conversion ...);
static yes_type _m_check(A, int);

int main() {
        B b;

        _m_check(b, 0);
}
```

Both GCC and Clang reject it.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net