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 , 8 years ago
comment:2 by , 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 , 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 , 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 , 8 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:5 by , 8 years ago
Milestone: | To Be Determined → Boost 1.58.0 |
---|---|
Resolution: | → wontfix |
Status: | assigned → closed |
Ping? Any updates on this?