From 24d29e5865ef51c1ad62d9a98c4f9dd2f25aed22 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 4 Nov 2018 17:35:10 +0300 Subject: [PATCH] Fix for clang, when adapted type is convertible from other types. The problem was with copy/move constructors of boost::optional, which invoked optional_base constructors with a single argument. Since optional_base has copy/move constructors along with initializing constructors taking a single argument, the latter may be considered by the compiler for viability. While doing so, the compiler may instantiate the template constructor of T with an argument of optional_base, which in turn may fail if the constructor attempts to inspect the type of its argument (e.g. to constrain the set of acceptable types). Specifically, this happens with clang in C++03 mode, when boost::multiprecision::number is wrapped in boost::optional and a copy constructor of boost::optional is invoked. This commit fixes the problem by destinguishing copy/move constructors of optional_base from initializing constructors with an additional tag argument. --- .../detail/optional_trivially_copyable_base.hpp | 2 +- include/boost/optional/optional.hpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/boost/optional/detail/optional_trivially_copyable_base.hpp b/include/boost/optional/detail/optional_trivially_copyable_base.hpp index 0734f62..5a37eac 100644 --- a/include/boost/optional/detail/optional_trivially_copyable_base.hpp +++ b/include/boost/optional/detail/optional_trivially_copyable_base.hpp @@ -30,7 +30,7 @@ class tc_optional_base : public optional_tag : m_initialized(false) {} - tc_optional_base ( argument_type val ) + tc_optional_base ( init_value_tag, argument_type val ) : m_initialized(true), m_storage(val) {} diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 104bca4..90acd40 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -107,7 +107,9 @@ using optional_ns::in_place_init_if; namespace optional_detail { -struct optional_tag {} ; +struct init_value_tag {}; + +struct optional_tag {}; template @@ -147,7 +149,7 @@ class optional_base : public optional_tag // Creates an optional initialized with 'val'. // Can throw if T::T(T const&) does - optional_base ( argument_type val ) + optional_base ( init_value_tag, argument_type val ) : m_initialized(false) { @@ -157,7 +159,7 @@ class optional_base : public optional_tag #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // move-construct an optional initialized from an rvalue-ref to 'val'. // Can throw if T::T(T&&) does - optional_base ( rval_reference_type val ) + optional_base ( init_value_tag, rval_reference_type val ) : m_initialized(false) { @@ -870,12 +872,12 @@ class optional // Creates an optional initialized with 'val'. // Can throw if T::T(T const&) does - optional ( argument_type val ) : base(val) {} + optional ( argument_type val ) : base(optional_detail::init_value_tag(), val) {} #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES // Creates an optional initialized with 'move(val)'. // Can throw if T::T(T &&) does - optional ( rval_reference_type val ) : base( boost::forward(val) ) + optional ( rval_reference_type val ) : base(optional_detail::init_value_tag(), boost::forward(val)) {} #endif