Boost logo

Boost Users :

Subject: Re: [Boost-users] [Boost.Optional] Compilation error with boost::optional in Boost 1.49 and GCC 4.4.6
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2012-04-27 17:44:14


On Fri, Apr 27, 2012 at 2:09 PM, Jonathan Jones <
Jonathan.Jones_at_[hidden]> wrote:

> On Apr 27, 2012, at 4:56 PM, Jeffrey Lee Hellrung, Jr. wrote:
>
> On Fri, Apr 27, 2012 at 12:47 PM, Jonathan Jones <
> Jonathan.Jones_at_[hidden]> wrote:
>
>> Hello,
>>
>> The following code fails to compile when using GCC 4.4.6 and
>> boost::optional from Boost 1.49:
>>
>
> Hmmm...seems to build fine for me with MSVC9 (also Boost 1.49.0)
>
>
> The problem seems specific to GCC. It compiles fine for me with MSVC 9
> and clang 2.1. I'm guessing this is in part due to the fact that with both
> those compilers, boost::is_convertible is implemented using compiler
> intrinsics, whereas this is not the case with GCC.
>
> #include <boost/optional/optional.hpp>
>> #include <boost/type_traits/is_convertible.hpp>
>>
>> struct grill
>> {
>> template<typename U>
>> grill (U)
>> {}
>> };
>>
>> template<typename T>
>> struct bar
>> {
>> template<typename U>
>> bar (U,
>> typename boost::is_convertible<U,T>::type* = 0)
>> {}
>> };
>>
>> void foo()
>> {
>> typedef bar<grill> data_type;
>>
>> boost::optional<data_type> opt;
>> boost::optional<data_type> opt2(opt); // this line
>> (void)opt2;
>> }
>>
>>
>> Here are the error messages (I apologize for the long lines, I shortened
>> them as much as possible by truncating the header paths):
>>
>>
>> type_traits/is_convertible.hpp: In instantiation of ‘const bool
>> boost::detail::is_convertible_basic_impl<boost::optional_detail::optional_base<bar<grill>
>> >&, grill>::value’:
>> type_traits/is_convertible.hpp:329: instantiated from ‘const bool
>> boost::detail::is_convertible_impl<boost::optional_detail::optional_base<bar<grill>
>> >, grill>::value’
>> type_traits/is_convertible.hpp:452: instantiated from
>> ‘boost::is_convertible<boost::optional_detail::optional_base<bar<grill> >,
>> grill>’
>> optional/optional.hpp:604: instantiated from
>> ‘boost::optional<T>::optional(const boost::optional<T>&) [with T =
>> bar<grill>]’
>> optional.cpp:25: instantiated from here
>> optional/optional.hpp:285: error:
>> ‘boost::optional_detail::optional_base<T>::optional_base(const
>> boost::optional_detail::optional_base<T>&) [with T = bar<grill>]’ is
>> protected
>> type_traits/is_convertible.hpp:170: error: within this context
>> type_traits/is_convertible.hpp:170: error: initializing argument 1 of
>> ‘grill::grill(U) [with U = boost::optional_detail::optional_base<bar<grill>
>> >]’
>> optional/optional.hpp:308: error:
>> ‘boost::optional_detail::optional_base<T>::~optional_base() [with T =
>> bar<grill>]’ is protected
>> type_traits/is_convertible.hpp:170: error: within this context
>>
>>
>> This reproduction case is distilled from a real world example (not my
>> code) where bar=boost::fusion::vector1 and grill=boost::function<void()>
>>
>> The code compiles fine using the same compiler and Boost 1.44.
>>
>> Any ideas on the root of the problem?
>>
>
> I can't figure it out from a quick glance through optional.hpp :( Can you
> investigate what has changed in optional.hpp between 1.44 and 1.49?
>
>
> I suspect the "breaking" change is this one:
> https://svn.boost.org/trac/boost/changeset/67183
>
> Note that on lines 560 and 594, a call to static_cast was added for copy
> construction and assignment. If I remove the static_cast, things start to
> compile again, but there isn't enough info in the change set as to why the
> static_casts were added.
>

I see. gcc must be investigating the viability of the
optional_base::optional_base(argument_type) and
optional_base::assign(argument_type) overloads (even though the
corresponding overloads taking an optional_base const & argument are
clearly preferable), and failing when seeing whether optional_base is
convertible to grill (indirectly from determining whether it is convertible
to bar<grill>), since this requires access to optional_base's copy
constructor since grill has a by-value converting constructor.

I have a hard time faulting the optional code, because sometimes you do
need to explicitly cast to the base type from the derived class to ensure
the right base class overload is used. I would be inclined to view an
unconstrained implicit conversion constructors like that exhibited in grill
suspiciously, but I can see its virtue within boost::fuction. I don't know.
Perhaps boost::function's constructor should be by reference? Or maybe the
static_cast's should be reverted? Or maybe
optional_base::optional_base(argument_type) should be changed to template<
class U > optional_base::optional_base(U&, typename enable_if_c< is_same<
U&, argument_type >::value >::type* = 0) ? I feel like there is a correct
thing to do here but it's escaping me :(

- Jeff



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