diff options
author | Ville Voutilainen <ville.voutilainen@gmail.com> | 2016-07-06 16:26:10 +0300 |
---|---|---|
committer | Ville Voutilainen <ville@gcc.gnu.org> | 2016-07-06 16:26:10 +0300 |
commit | 6ffe854859e61fd04e1db8694e2c519f4010647b (patch) | |
tree | 957dd6c8746ccbf44024331b3ac6724659ec9dbe | |
parent | e4bbb037670323fbc578b6bc68cfb5252f1bf0cc (diff) | |
download | gcc-6ffe854859e61fd04e1db8694e2c519f4010647b.zip gcc-6ffe854859e61fd04e1db8694e2c519f4010647b.tar.gz gcc-6ffe854859e61fd04e1db8694e2c519f4010647b.tar.bz2 |
Implement LWG 2451, optional<T> should 'forward' T's implicit conversions.
Implement LWG 2451, optional<T> should 'forward' T's
implicit conversions.
* include/experimental/optional (__is_optional_impl, __is_optional):
New.
(optional()): Make constexpr and default.
(optional(_Up&&), optional(const optional<_Up>&),
optional(optional<_Up>&& __t): New.
(operator=(_Up&&)): Constrain.
(operator=(const optional<_Up>&), operator=(optional<_Up>&&)): New.
* testsuite/experimental/optional/cons/value.cc:
Add tests for the functionality added by LWG 2451.
* testsuite/experimental/optional/cons/value_neg.cc: New.
From-SVN: r238049
-rw-r--r-- | libstdc++-v3/ChangeLog | 15 | ||||
-rw-r--r-- | libstdc++-v3/include/experimental/optional | 148 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/optional/cons/value.cc | 19 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc | 39 |
4 files changed, 219 insertions, 2 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d888864..46f7f74 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2016-07-06 Ville Voutilainen <ville.voutilainen@gmail.com> + + Implement LWG 2451, optional<T> should 'forward' T's + implicit conversions. + * include/experimental/optional (__is_optional_impl, __is_optional): + New. + (optional()): Make constexpr and default. + (optional(_Up&&), optional(const optional<_Up>&), + optional(optional<_Up>&& __t): New. + (operator=(_Up&&)): Constrain. + (operator=(const optional<_Up>&), operator=(optional<_Up>&&)): New. + * testsuite/experimental/optional/cons/value.cc: + Add tests for the functionality added by LWG 2451. + * testsuite/experimental/optional/cons/value_neg.cc: New. + 2016-07-05 Ville Voutilainen <ville.voutilainen@gmail.com> Implement LWG 2509, diff --git a/libstdc++-v3/include/experimental/optional b/libstdc++-v3/include/experimental/optional index 7524a7e..b6425b7 100644 --- a/libstdc++-v3/include/experimental/optional +++ b/libstdc++-v3/include/experimental/optional @@ -470,6 +470,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool _M_engaged = false; }; + template<typename _Tp> + class optional; + + template<typename> + struct __is_optional_impl : false_type + { }; + + template<typename _Tp> + struct __is_optional_impl<optional<_Tp>> : true_type + { }; + + template<typename _Tp> + struct __is_optional + : public __is_optional_impl<std::remove_cv_t<std::remove_reference_t<_Tp>>> + { }; + + /** * @brief Class template for optional values. */ @@ -502,6 +519,78 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _Optional_base has the responsibility for construction. using _Base::_Base; + constexpr optional() = default; + // Converting constructors for engaged optionals. + template <typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp> + >::value, bool> = true> + constexpr optional(_Up&& __t) + : _Base(_Tp(std::forward<_Up>(__t))) { } + + template <typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>, + is_constructible<_Tp, _Up&&>, + __not_<is_convertible<_Up&&, _Tp>> + >::value, bool> = false> + explicit constexpr optional(_Up&& __t) + : _Base(_Tp(std::forward<_Up>(__t))) { } + + template <typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>, + __not_<is_constructible< + _Tp, const optional<_Up>&>>, + __not_<is_convertible< + const optional<_Up>&, _Tp>>, + is_constructible<_Tp, const _Up&>, + is_convertible<const _Up&, _Tp> + >::value, bool> = true> + constexpr optional(const optional<_Up>& __t) + : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { } + + template <typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>, + __not_<is_constructible< + _Tp, const optional<_Up>&>>, + __not_<is_convertible< + const optional<_Up>&, _Tp>>, + is_constructible<_Tp, const _Up&>, + __not_<is_convertible<const _Up&, _Tp>> + >::value, bool> = false> + explicit constexpr optional(const optional<_Up>& __t) + : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { } + + template <typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>, + __not_<is_constructible< + _Tp, optional<_Up>&&>>, + __not_<is_convertible< + optional<_Up>&&, _Tp>>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp> + >::value, bool> = true> + constexpr optional(optional<_Up>&& __t) + : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { } + + template <typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>, + __not_<is_constructible< + _Tp, optional<_Up>&&>>, + __not_<is_convertible< + optional<_Up>&&, _Tp>>, + is_constructible<_Tp, _Up&&>, + __not_<is_convertible<_Up&&, _Tp>> + >::value, bool> = false> + explicit constexpr optional(optional<_Up>&& __t) + : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { } + // [X.Y.4.3] (partly) Assignment. optional& operator=(nullopt_t) noexcept @@ -510,8 +599,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template<typename _Up> - enable_if_t<is_same<_Tp, decay_t<_Up>>::value, optional&> + template<typename _Up, + enable_if_t<__and_< + __not_<is_same<_Up, nullopt_t>>, + __not_<__is_optional<_Up>>>::value, + bool> = true> + optional& operator=(_Up&& __u) { static_assert(__and_<is_constructible<_Tp, _Up>, @@ -526,6 +619,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } + template<typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>>::value, + bool> = true> + optional& + operator=(const optional<_Up>& __u) + { + static_assert(__and_<is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>(), + "Cannot assign to value type from argument"); + + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template<typename _Up, + enable_if_t<__and_< + __not_<is_same<_Tp, _Up>>>::value, + bool> = true> + optional& + operator=(optional<_Up>&& __u) + { + static_assert(__and_<is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>(), + "Cannot assign to value type from argument"); + + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + template<typename... _Args> void emplace(_Args&&... __args) diff --git a/libstdc++-v3/testsuite/experimental/optional/cons/value.cc b/libstdc++-v3/testsuite/experimental/optional/cons/value.cc index a916951..123a89e 100644 --- a/libstdc++-v3/testsuite/experimental/optional/cons/value.cc +++ b/libstdc++-v3/testsuite/experimental/optional/cons/value.cc @@ -22,6 +22,7 @@ #include <testsuite_hooks.h> #include <vector> +#include <string> struct tracker { @@ -236,4 +237,22 @@ int main() VERIFY( result == caught ); } + + { + std::experimental::optional<std::string> os = "foo"; + struct X + { + explicit X(int) {} + X& operator=(int) {return *this;} + }; + std::experimental::optional<X> ox{42}; + std::experimental::optional<int> oi{42}; + std::experimental::optional<X> ox2{oi}; + std::experimental::optional<std::string> os2; + os2 = "foo"; + std::experimental::optional<X> ox3; + ox3 = 42; + std::experimental::optional<X> ox4; + ox4 = oi; + } } diff --git a/libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc b/libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc new file mode 100644 index 0000000..c862a04 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc @@ -0,0 +1,39 @@ +// { dg-options "-std=gnu++14" } +// { dg-do compile } + +// Copyright (C) 2013-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a moved_to of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <experimental/optional> +#include <testsuite_hooks.h> + +#include <string> +#include <memory> + +int main() +{ + { + struct X + { + explicit X(int) {} + }; + std::experimental::optional<X> ox{42}; + std::experimental::optional<X> ox2 = 42; // { dg-error "conversion" } + std::experimental::optional<std::unique_ptr<int>> oup{new int}; + std::experimental::optional<std::unique_ptr<int>> oup2 = new int; // { dg-error "conversion" } + } +} |