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
This commit is contained in:
Ville Voutilainen 2016-07-06 16:26:10 +03:00 committed by Ville Voutilainen
parent e4bbb03767
commit 6ffe854859
4 changed files with 219 additions and 2 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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" }
}
}