diff -up chromium-65.0.3325.146/base/optional.h.converting chromium-65.0.3325.146/base/optional.h --- chromium-65.0.3325.146/base/optional.h.converting 2018-03-13 22:31:05.248797490 -0400 +++ chromium-65.0.3325.146/base/optional.h 2018-03-13 22:33:10.826368771 -0400 @@ -31,6 +31,10 @@ constexpr in_place_t in_place = {}; // http://en.cppreference.com/w/cpp/utility/optional/nullopt constexpr nullopt_t nullopt(0); +// Forward declaration, which is refered by following helpers. +template +class Optional; + namespace internal { template ::value> @@ -220,6 +224,19 @@ class OptionalBase { constexpr explicit OptionalBase(in_place_t, Args&&... args) : storage_(in_place, std::forward(args)...) {} + // Implementation of converting constructors. + template + explicit OptionalBase(const OptionalBase& other) { + if (other.storage_.is_populated_) + storage_.Init(other.storage_.value_); + } + + template + explicit OptionalBase(OptionalBase&& other) { + if (other.storage_.is_populated_) + storage_.Init(std::move(other.storage_.value_)); + } + ~OptionalBase() = default; OptionalBase& operator=(const OptionalBase& other) { @@ -263,6 +280,11 @@ class OptionalBase { storage_.is_populated_ = false; } + // For implementing conversion, allow access to other typed OptionalBase + // class. + template + friend class OptionalBase; + OptionalStorage storage_; }; @@ -318,6 +340,20 @@ struct MoveAssignable { MoveAssignable& operator=(MoveAssignable&&) = delete; }; +// Helper to conditionally enable converting constructors. +template +struct IsConvertibleFromOptional + : std::integral_constant< + bool, + std::is_constructible&>::value || + std::is_constructible&>::value || + std::is_constructible&&>::value || + std::is_constructible&&>::value || + std::is_convertible&, T>::value || + std::is_convertible&, T>::value || + std::is_convertible&&, T>::value || + std::is_convertible&&, T>::value> {}; + } // namespace internal // base::Optional is a Chromium version of the C++17 optional class: @@ -348,7 +384,47 @@ class Optional constexpr Optional(const Optional& other) = default; constexpr Optional(Optional&& other) = default; - constexpr Optional(nullopt_t) {} + constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit) + + // Converting copy constructor. "explicit" only if + // std::is_convertible::value is false. It is implemented by + // declaring two almost same constructors, but that condition in enable_if_t + // is different, so that either one is chosen, thanks to SFINAE. + template < + typename U, + std::enable_if_t::value && + !internal::IsConvertibleFromOptional::value && + std::is_convertible::value, + bool> = false> + Optional(const Optional& other) : internal::OptionalBase(other) {} + + template < + typename U, + std::enable_if_t::value && + !internal::IsConvertibleFromOptional::value && + !std::is_convertible::value, + bool> = false> + explicit Optional(const Optional& other) + : internal::OptionalBase(other) {} + + // Converting move constructor. Similar to converting copy constructor, + // declaring two (explicit and non-explicit) constructors. + template < + typename U, + std::enable_if_t::value && + !internal::IsConvertibleFromOptional::value && + std::is_convertible::value, + bool> = false> + Optional(Optional&& other) : internal::OptionalBase(std::move(other)) {} + + template < + typename U, + std::enable_if_t::value && + !internal::IsConvertibleFromOptional::value && + !std::is_convertible::value, + bool> = false> + explicit Optional(Optional&& other) + : internal::OptionalBase(std::move(other)) {} constexpr Optional(const T& value) : internal::OptionalBase(in_place, value) {}