Opened 8 years ago

Closed 8 years ago

#10399 closed Bugs (wontfix)

Breaking change in Boost.Optional

Reported by: Dean Michael Berris Owned by: akrzemi1
Milestone: Boost 1.58.0 Component: optional
Version: Boost 1.54.0 Severity: Regression
Keywords: optional regression Cc:

Description

Suppose I have the following types:

    struct container {
      boost::optional<uint16_t> optional() const {
        return value_;
      }
     private:
      boost::optional<uint16_t> value_;
    };

    struct value_wrapper {
      value_wrapper(const container& c) : c_(c) {}
      operator uint16_t () { return 1; }
      operator boost::optional<uint16_t>() { return c_.optional(); }
     private:
      const container& c_;
    };

And that I have the following function:

    value_wrapper value(const container& c) {
      return value_wrapper(c);
    }

The following used to work in MSVC 2010:

    container c;
    // leave c.value_ alone.
    boost::optional<uint16_t> some_value =
      value(c);
    assert(!some_value);

Now with Boost 1.56, this breaks because the constructor for some_value from a temporary optional is now marked explicit.

What is the work-around for the previous behavior to be regained? All the following changes cause the assertion to fail:

    boost::optional<uint16_t> some_value(value(c));
    assert(!some_value);  // some_value's constructor will use the
    uint16_t conversion operator, therefore some_value == 1

    boost::optional<uint16_t> some_value =
    static_cast<boost::optional<uint16_t> >(value(c));
    assert(!some_value);  // same problem as above, 
                          // the temporary created will favor
                          // the uint16_t conversion operator

Help?

PS. For better context, see https://github.com/cpp-netlib/cpp-netlib/blob/0.11-devel/boost/network/protocol/http/algorithms/linearize.hpp#L145

Change History (6)

comment:1 by Dean Michael Berris, 8 years ago

Ping? Any updates on this?

comment:2 by akrzemi1, 8 years ago

This is caused by a compiler bug in MSVC, see https://connect.microsoft.com/VisualStudio/feedback/details/967397/incorrect-conversion-handling-in-c. This was added when implementing move semantics and cannot be taken out without taking move semantics out. I could forcibly counteract Microsoft double conversions, but do not feel that this is a good idea. The problem is also observable in Boost.Variant, and no-one seams to be questioning it implementing move semantics:

#include <boost/variant.hpp>

struct Wrapper
{
  operator int () { return 9; }
  operator boost::variant<int, long> () { return 7; }
};

int main()
{
  boost::variant<int, long> v = Wrapper();
  assert(boost::get<int>(v) == 7);
} 

comment:3 by anonymous, 8 years ago

It is now possible to manually disable move operations. Just define macro BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES This eliminates the problem on MSVC.

comment:3 by anonymous, 8 years ago

It is now possible to manually disable move operations. Just define macro BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES This eliminates the problem on MSVC.

comment:4 by akrzemi1, 8 years ago

Owner: changed from Fernando Cacciola to akrzemi1
Status: newassigned

comment:5 by akrzemi1, 8 years ago

Milestone: To Be DeterminedBoost 1.58.0
Resolution: wontfix
Status: assignedclosed
Note: See TracTickets for help on using tickets.