2016-08-18 22:31:26 +02:00
|
|
|
// <variant> -*- C++ -*-
|
|
|
|
|
2020-01-01 12:51:42 +01:00
|
|
|
// Copyright (C) 2016-2020 Free Software Foundation, Inc.
|
2016-08-18 22:31:26 +02:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
/** @file variant
|
|
|
|
* This is the <variant> C++ Library header.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _GLIBCXX_VARIANT
|
|
|
|
#define _GLIBCXX_VARIANT 1
|
|
|
|
|
|
|
|
#pragma GCC system_header
|
|
|
|
|
2017-09-12 16:02:59 +02:00
|
|
|
#if __cplusplus >= 201703L
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
|
|
|
#include <bits/enable_special_members.h>
|
2016-10-14 11:58:05 +02:00
|
|
|
#include <bits/functexcept.h>
|
2016-09-05 21:52:11 +02:00
|
|
|
#include <bits/move.h>
|
2016-11-14 22:22:53 +01:00
|
|
|
#include <bits/functional_hash.h>
|
2016-12-06 12:28:09 +01:00
|
|
|
#include <bits/invoke.h>
|
2016-12-06 12:20:13 +01:00
|
|
|
#include <ext/aligned_buffer.h>
|
2017-01-11 12:23:43 +01:00
|
|
|
#include <bits/parse_numbers.h>
|
2017-06-05 18:49:04 +02:00
|
|
|
#include <bits/stl_iterator_base_types.h>
|
|
|
|
#include <bits/stl_iterator_base_funcs.h>
|
|
|
|
#include <bits/stl_construct.h>
|
2020-02-21 13:02:15 +01:00
|
|
|
#if __cplusplus > 201703L
|
|
|
|
# include <compare>
|
|
|
|
#endif
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
|
|
{
|
2017-07-23 10:41:35 +02:00
|
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
|
2016-12-06 12:28:09 +01:00
|
|
|
namespace __detail
|
|
|
|
{
|
|
|
|
namespace __variant
|
|
|
|
{
|
|
|
|
template<size_t _Np, typename... _Types>
|
|
|
|
struct _Nth_type;
|
|
|
|
|
|
|
|
template<size_t _Np, typename _First, typename... _Rest>
|
|
|
|
struct _Nth_type<_Np, _First, _Rest...>
|
|
|
|
: _Nth_type<_Np-1, _Rest...> { };
|
|
|
|
|
|
|
|
template<typename _First, typename... _Rest>
|
|
|
|
struct _Nth_type<0, _First, _Rest...>
|
|
|
|
{ using type = _First; };
|
|
|
|
|
|
|
|
} // namespace __variant
|
|
|
|
} // namespace __detail
|
|
|
|
|
2019-01-15 13:01:12 +01:00
|
|
|
#define __cpp_lib_variant 201606L
|
2017-09-12 16:02:59 +02:00
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename... _Types> class tuple;
|
|
|
|
template<typename... _Types> class variant;
|
|
|
|
template <typename> struct hash;
|
|
|
|
|
|
|
|
template<typename _Variant>
|
|
|
|
struct variant_size;
|
|
|
|
|
|
|
|
template<typename _Variant>
|
|
|
|
struct variant_size<const _Variant> : variant_size<_Variant> {};
|
|
|
|
|
|
|
|
template<typename _Variant>
|
|
|
|
struct variant_size<volatile _Variant> : variant_size<_Variant> {};
|
|
|
|
|
|
|
|
template<typename _Variant>
|
|
|
|
struct variant_size<const volatile _Variant> : variant_size<_Variant> {};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
struct variant_size<variant<_Types...>>
|
|
|
|
: std::integral_constant<size_t, sizeof...(_Types)> {};
|
|
|
|
|
|
|
|
template<typename _Variant>
|
Implement P0607R0 "Inline Variables for Standard Library" for C++17
2017-03-23 Daniel Kruegler <daniel.kruegler@gmail.com>
* include/bits/c++config (_GLIBCXX17_INLINE): Define.
* include/bits/regex_constants.h (All std::regex_constants constants):
Add _GLIBCXX17_INLINE as per P0607R0.
* include/bits/std_mutex.h (defer_lock, try_to_lock, adopt_lock):
Likewise.
* include/bits/stl_pair.h (piecewise_construct): Likewise.
* include/bits/uses_allocator.h (allocator_arg, uses_allocator_v)
(__is_uses_allocator_constructible_v)
(__is_nothrow_uses_allocator_constructible_v): Likewise.
* include/std/chrono (treat_as_floating_point_v): Likewise.
* include/std/functional (is_bind_expression_v, is_placeholder_v):
Likewise.
* include/std/optional (nullopt): Likewise.
* include/std/ratio (ratio_equal_v, ratio_not_equal_v, ratio_less_v)
ratio_less_equal_v, ratio_greater_v, ratio_greater_equal_v): Likewise.
* include/std/system_error (is_error_code_enum_v)
(is_error_condition_enum_v): Likewise.
* include/std/tuple (tuple_size_v, ignore): Likewise.
(ignore): Declare ignore constexpr as per LWG 2773, declare assignment
constexpr as per LWG 2933.
* include/std/type_traits (All variable templates): Add
_GLIBCXX17_INLINE as per P0607R0.
* include/std/variant (variant_size_v, variant_npos, __index_of_v)
(__tuple_count_v, __exactly_once): Likewise.
* testsuite/18_support/headers/new/synopsis.cc
(hardware_destructive_interference_size)
(hardware_constructive_interference_size): Likewise for commented-out
variables.
* testsuite/20_util/tuple/creation_functions/constexpr.cc: Add new
test function for constexpr std::ignore (LWG 2773).
* testsuite/20_util/tuple/creation_functions/constexpr_cpp14.cc: New
test for LWG 2933.
From-SVN: r246423
2017-03-23 20:40:07 +01:00
|
|
|
inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<size_t _Np, typename _Variant>
|
|
|
|
struct variant_alternative;
|
|
|
|
|
|
|
|
template<size_t _Np, typename _First, typename... _Rest>
|
|
|
|
struct variant_alternative<_Np, variant<_First, _Rest...>>
|
|
|
|
: variant_alternative<_Np-1, variant<_Rest...>> {};
|
|
|
|
|
|
|
|
template<typename _First, typename... _Rest>
|
|
|
|
struct variant_alternative<0, variant<_First, _Rest...>>
|
|
|
|
{ using type = _First; };
|
|
|
|
|
|
|
|
template<size_t _Np, typename _Variant>
|
|
|
|
using variant_alternative_t =
|
|
|
|
typename variant_alternative<_Np, _Variant>::type;
|
|
|
|
|
2016-11-27 01:32:04 +01:00
|
|
|
template<size_t _Np, typename _Variant>
|
|
|
|
struct variant_alternative<_Np, const _Variant>
|
|
|
|
{ using type = add_const_t<variant_alternative_t<_Np, _Variant>>; };
|
|
|
|
|
|
|
|
template<size_t _Np, typename _Variant>
|
|
|
|
struct variant_alternative<_Np, volatile _Variant>
|
|
|
|
{ using type = add_volatile_t<variant_alternative_t<_Np, _Variant>>; };
|
|
|
|
|
|
|
|
template<size_t _Np, typename _Variant>
|
|
|
|
struct variant_alternative<_Np, const volatile _Variant>
|
|
|
|
{ using type = add_cv_t<variant_alternative_t<_Np, _Variant>>; };
|
|
|
|
|
Implement P0607R0 "Inline Variables for Standard Library" for C++17
2017-03-23 Daniel Kruegler <daniel.kruegler@gmail.com>
* include/bits/c++config (_GLIBCXX17_INLINE): Define.
* include/bits/regex_constants.h (All std::regex_constants constants):
Add _GLIBCXX17_INLINE as per P0607R0.
* include/bits/std_mutex.h (defer_lock, try_to_lock, adopt_lock):
Likewise.
* include/bits/stl_pair.h (piecewise_construct): Likewise.
* include/bits/uses_allocator.h (allocator_arg, uses_allocator_v)
(__is_uses_allocator_constructible_v)
(__is_nothrow_uses_allocator_constructible_v): Likewise.
* include/std/chrono (treat_as_floating_point_v): Likewise.
* include/std/functional (is_bind_expression_v, is_placeholder_v):
Likewise.
* include/std/optional (nullopt): Likewise.
* include/std/ratio (ratio_equal_v, ratio_not_equal_v, ratio_less_v)
ratio_less_equal_v, ratio_greater_v, ratio_greater_equal_v): Likewise.
* include/std/system_error (is_error_code_enum_v)
(is_error_condition_enum_v): Likewise.
* include/std/tuple (tuple_size_v, ignore): Likewise.
(ignore): Declare ignore constexpr as per LWG 2773, declare assignment
constexpr as per LWG 2933.
* include/std/type_traits (All variable templates): Add
_GLIBCXX17_INLINE as per P0607R0.
* include/std/variant (variant_size_v, variant_npos, __index_of_v)
(__tuple_count_v, __exactly_once): Likewise.
* testsuite/18_support/headers/new/synopsis.cc
(hardware_destructive_interference_size)
(hardware_constructive_interference_size): Likewise for commented-out
variables.
* testsuite/20_util/tuple/creation_functions/constexpr.cc: Add new
test function for constexpr std::ignore (LWG 2773).
* testsuite/20_util/tuple/creation_functions/constexpr_cpp14.cc: New
test for LWG 2933.
From-SVN: r246423
2017-03-23 20:40:07 +01:00
|
|
|
inline constexpr size_t variant_npos = -1;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2016-12-06 12:28:09 +01:00
|
|
|
template<size_t _Np, typename... _Types>
|
|
|
|
constexpr variant_alternative_t<_Np, variant<_Types...>>&
|
|
|
|
get(variant<_Types...>&);
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
|
|
|
constexpr variant_alternative_t<_Np, variant<_Types...>>&&
|
|
|
|
get(variant<_Types...>&&);
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
|
|
|
constexpr variant_alternative_t<_Np, variant<_Types...>> const&
|
|
|
|
get(const variant<_Types...>&);
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
|
|
|
constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
|
|
|
|
get(const variant<_Types...>&&);
|
|
|
|
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename _Result_type, typename _Visitor, typename... _Variants>
|
2019-03-06 13:56:05 +01:00
|
|
|
constexpr decltype(auto)
|
|
|
|
__do_visit(_Visitor&& __visitor, _Variants&&... __variants);
|
|
|
|
|
|
|
|
template <typename... _Types, typename _Tp>
|
2019-04-09 20:50:48 +02:00
|
|
|
decltype(auto)
|
|
|
|
__variant_cast(_Tp&& __rhs)
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
|
|
|
if constexpr (is_lvalue_reference_v<_Tp>)
|
|
|
|
{
|
|
|
|
if constexpr (is_const_v<remove_reference_t<_Tp>>)
|
|
|
|
return static_cast<const variant<_Types...>&>(__rhs);
|
|
|
|
else
|
|
|
|
return static_cast<variant<_Types...>&>(__rhs);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return static_cast<variant<_Types...>&&>(__rhs);
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
namespace __detail
|
|
|
|
{
|
|
|
|
namespace __variant
|
|
|
|
{
|
2020-06-23 11:24:49 +02:00
|
|
|
// Returns the first appearance of _Tp in _Types.
|
2016-08-18 22:31:26 +02:00
|
|
|
// Returns sizeof...(_Types) if _Tp is not in _Types.
|
|
|
|
template<typename _Tp, typename... _Types>
|
|
|
|
struct __index_of : std::integral_constant<size_t, 0> {};
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
Implement P0607R0 "Inline Variables for Standard Library" for C++17
2017-03-23 Daniel Kruegler <daniel.kruegler@gmail.com>
* include/bits/c++config (_GLIBCXX17_INLINE): Define.
* include/bits/regex_constants.h (All std::regex_constants constants):
Add _GLIBCXX17_INLINE as per P0607R0.
* include/bits/std_mutex.h (defer_lock, try_to_lock, adopt_lock):
Likewise.
* include/bits/stl_pair.h (piecewise_construct): Likewise.
* include/bits/uses_allocator.h (allocator_arg, uses_allocator_v)
(__is_uses_allocator_constructible_v)
(__is_nothrow_uses_allocator_constructible_v): Likewise.
* include/std/chrono (treat_as_floating_point_v): Likewise.
* include/std/functional (is_bind_expression_v, is_placeholder_v):
Likewise.
* include/std/optional (nullopt): Likewise.
* include/std/ratio (ratio_equal_v, ratio_not_equal_v, ratio_less_v)
ratio_less_equal_v, ratio_greater_v, ratio_greater_equal_v): Likewise.
* include/std/system_error (is_error_code_enum_v)
(is_error_condition_enum_v): Likewise.
* include/std/tuple (tuple_size_v, ignore): Likewise.
(ignore): Declare ignore constexpr as per LWG 2773, declare assignment
constexpr as per LWG 2933.
* include/std/type_traits (All variable templates): Add
_GLIBCXX17_INLINE as per P0607R0.
* include/std/variant (variant_size_v, variant_npos, __index_of_v)
(__tuple_count_v, __exactly_once): Likewise.
* testsuite/18_support/headers/new/synopsis.cc
(hardware_destructive_interference_size)
(hardware_constructive_interference_size): Likewise for commented-out
variables.
* testsuite/20_util/tuple/creation_functions/constexpr.cc: Add new
test function for constexpr std::ignore (LWG 2773).
* testsuite/20_util/tuple/creation_functions/constexpr_cpp14.cc: New
test for LWG 2933.
From-SVN: r246423
2017-03-23 20:40:07 +01:00
|
|
|
inline constexpr size_t __index_of_v = __index_of<_Tp, _Types...>::value;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _Tp, typename _First, typename... _Rest>
|
|
|
|
struct __index_of<_Tp, _First, _Rest...> :
|
|
|
|
std::integral_constant<size_t, is_same_v<_Tp, _First>
|
|
|
|
? 0 : __index_of_v<_Tp, _Rest...> + 1> {};
|
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
// used for raw visitation
|
|
|
|
struct __variant_cookie {};
|
2019-04-01 15:57:41 +02:00
|
|
|
// used for raw visitation with indices passed in
|
2019-04-09 20:50:43 +02:00
|
|
|
struct __variant_idx_cookie { using type = __variant_idx_cookie; };
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// Used to enable deduction (and same-type checking) for std::visit:
|
|
|
|
template<typename> struct __deduce_visit_result { };
|
|
|
|
|
|
|
|
// Visit variants that might be valueless.
|
|
|
|
template<typename _Visitor, typename... _Variants>
|
|
|
|
constexpr void
|
|
|
|
__raw_visit(_Visitor&& __visitor, _Variants&&... __variants)
|
|
|
|
{
|
|
|
|
std::__do_visit<__variant_cookie>(std::forward<_Visitor>(__visitor),
|
|
|
|
std::forward<_Variants>(__variants)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Visit variants that might be valueless, passing indices to the visitor.
|
|
|
|
template<typename _Visitor, typename... _Variants>
|
|
|
|
constexpr void
|
|
|
|
__raw_idx_visit(_Visitor&& __visitor, _Variants&&... __variants)
|
|
|
|
{
|
|
|
|
std::__do_visit<__variant_idx_cookie>(std::forward<_Visitor>(__visitor),
|
|
|
|
std::forward<_Variants>(__variants)...);
|
|
|
|
}
|
2019-03-06 13:56:05 +01:00
|
|
|
|
2020-06-28 23:36:38 +02:00
|
|
|
// _Uninitialized<T> is guaranteed to be a trivially destructible type,
|
|
|
|
// even if T is not.
|
|
|
|
template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
|
2016-08-18 22:31:26 +02:00
|
|
|
struct _Uninitialized;
|
|
|
|
|
|
|
|
template<typename _Type>
|
|
|
|
struct _Uninitialized<_Type, true>
|
|
|
|
{
|
|
|
|
template<typename... _Args>
|
2019-04-09 20:50:48 +02:00
|
|
|
constexpr
|
|
|
|
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
|
|
|
|
: _M_storage(std::forward<_Args>(__args)...)
|
|
|
|
{ }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr const _Type& _M_get() const & noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return _M_storage; }
|
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr _Type& _M_get() & noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return _M_storage; }
|
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr const _Type&& _M_get() const && noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return std::move(_M_storage); }
|
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr _Type&& _M_get() && noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return std::move(_M_storage); }
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
_Type _M_storage;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename _Type>
|
|
|
|
struct _Uninitialized<_Type, false>
|
|
|
|
{
|
|
|
|
template<typename... _Args>
|
2019-04-09 20:50:48 +02:00
|
|
|
constexpr
|
|
|
|
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
|
|
|
|
{
|
|
|
|
::new ((void*)std::addressof(_M_storage))
|
|
|
|
_Type(std::forward<_Args>(__args)...);
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
const _Type& _M_get() const & noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return *_M_storage._M_ptr(); }
|
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
_Type& _M_get() & noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return *_M_storage._M_ptr(); }
|
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
const _Type&& _M_get() const && noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return std::move(*_M_storage._M_ptr()); }
|
|
|
|
|
2019-04-23 11:55:28 +02:00
|
|
|
_Type&& _M_get() && noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return std::move(*_M_storage._M_ptr()); }
|
|
|
|
|
|
|
|
__gnu_cxx::__aligned_membuf<_Type> _M_storage;
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
template<typename _Union>
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr decltype(auto)
|
|
|
|
__get(in_place_index_t<0>, _Union&& __u) noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{ return std::forward<_Union>(__u)._M_first._M_get(); }
|
|
|
|
|
|
|
|
template<size_t _Np, typename _Union>
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr decltype(auto)
|
|
|
|
__get(in_place_index_t<_Np>, _Union&& __u) noexcept
|
2018-03-26 15:09:10 +02:00
|
|
|
{
|
|
|
|
return __variant::__get(in_place_index<_Np-1>,
|
|
|
|
std::forward<_Union>(__u)._M_rest);
|
|
|
|
}
|
2016-12-06 12:20:13 +01:00
|
|
|
|
|
|
|
// Returns the typed storage for __v.
|
|
|
|
template<size_t _Np, typename _Variant>
|
2019-04-23 11:55:28 +02:00
|
|
|
constexpr decltype(auto)
|
|
|
|
__get(_Variant&& __v) noexcept
|
2016-12-06 12:20:13 +01:00
|
|
|
{
|
2018-03-26 15:09:10 +02:00
|
|
|
return __variant::__get(std::in_place_index<_Np>,
|
|
|
|
std::forward<_Variant>(__v)._M_u);
|
2016-12-06 12:20:13 +01:00
|
|
|
}
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
template<typename... _Types>
|
|
|
|
struct _Traits
|
|
|
|
{
|
|
|
|
static constexpr bool _S_default_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_copy_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
(is_copy_constructible_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_move_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
(is_move_constructible_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_copy_assign =
|
2019-04-17 21:27:27 +02:00
|
|
|
_S_copy_ctor
|
2017-07-23 10:41:35 +02:00
|
|
|
&& (is_copy_assignable_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_move_assign =
|
2017-07-23 10:41:35 +02:00
|
|
|
_S_move_ctor
|
|
|
|
&& (is_move_assignable_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
|
|
|
|
static constexpr bool _S_trivial_dtor =
|
2017-07-23 10:41:35 +02:00
|
|
|
(is_trivially_destructible_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_trivial_copy_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
(is_trivially_copy_constructible_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_trivial_move_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
(is_trivially_move_constructible_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_trivial_copy_assign =
|
2019-04-23 14:48:28 +02:00
|
|
|
_S_trivial_dtor && _S_trivial_copy_ctor
|
|
|
|
&& (is_trivially_copy_assignable_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_trivial_move_assign =
|
2019-04-23 14:48:28 +02:00
|
|
|
_S_trivial_dtor && _S_trivial_move_ctor
|
|
|
|
&& (is_trivially_move_assignable_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
|
|
|
|
// The following nothrow traits are for non-trivial SMFs. Trivial SMFs
|
|
|
|
// are always nothrow.
|
|
|
|
static constexpr bool _S_nothrow_default_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
is_nothrow_default_constructible_v<
|
|
|
|
typename _Nth_type<0, _Types...>::type>;
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_nothrow_copy_ctor = false;
|
|
|
|
static constexpr bool _S_nothrow_move_ctor =
|
2017-07-23 10:41:35 +02:00
|
|
|
(is_nothrow_move_constructible_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
static constexpr bool _S_nothrow_copy_assign = false;
|
|
|
|
static constexpr bool _S_nothrow_move_assign =
|
2019-04-23 14:48:28 +02:00
|
|
|
_S_nothrow_move_ctor
|
|
|
|
&& (is_nothrow_move_assignable_v<_Types> && ...);
|
2017-06-27 20:19:03 +02:00
|
|
|
};
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
// Defines members and ctors.
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename... _Types>
|
2016-12-06 12:20:13 +01:00
|
|
|
union _Variadic_union { };
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _First, typename... _Rest>
|
2016-12-06 12:20:13 +01:00
|
|
|
union _Variadic_union<_First, _Rest...>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2016-12-06 12:20:13 +01:00
|
|
|
constexpr _Variadic_union() : _M_rest() { }
|
|
|
|
|
|
|
|
template<typename... _Args>
|
|
|
|
constexpr _Variadic_union(in_place_index_t<0>, _Args&&... __args)
|
|
|
|
: _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Args>
|
|
|
|
constexpr _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
|
|
|
|
: _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
_Uninitialized<_First> _M_first;
|
|
|
|
_Variadic_union<_Rest...> _M_rest;
|
|
|
|
};
|
|
|
|
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// _Never_valueless_alt is true for variant alternatives that can
|
|
|
|
// always be placed in a variant without it becoming valueless.
|
|
|
|
|
|
|
|
// For suitably-small, trivially copyable types we can create temporaries
|
|
|
|
// on the stack and then memcpy them into place.
|
|
|
|
template<typename _Tp>
|
|
|
|
struct _Never_valueless_alt
|
|
|
|
: __and_<bool_constant<sizeof(_Tp) <= 256>, is_trivially_copyable<_Tp>>
|
|
|
|
{ };
|
|
|
|
|
|
|
|
// Specialize _Never_valueless_alt for other types which have a
|
Fix std::variant regression caused by never-valueless optimization
A regression was introduced by the recent changes to provide the strong
exception safety guarantee for "never valueless" types that have O(1),
non-throwing move assignment. The problematic code is:
else if constexpr (__detail::__variant::_Never_valueless_alt<type>())
{
// This construction might throw:
variant __tmp(in_place_index<_Np>, __il,
std::forward<_Args>(__args)...);
// But _Never_valueless_alt<type> means this won't:
*this = std::move(__tmp);
}
When the variant is not assignable, the assignment is ill-formed, so
should not be attempted. When the variant has a copy assignment operator
but not a move assignment operator, the assignment performs a copy
assignment and that could throw, so should not be attempted.
The solution is to only take that branch when the variant has a move
assignment operator, which is determined by the _Traits::_S_move_assign
constant. When that is false the strong exception safety guarantee is
not possible, and so the __never_valueless function should also depend
on _S_move_assign.
While testing the fixes for this I noticed that the partial
specialization _Never_valueless_alt<basic_string<C,T,A>> incorrectly
assumed that is_nothrow_move_constructible<basic_string<C,T,A>> is
always true, but that's wrong for fully-dynamic COW strings. Fix the
partial specialization, and improve the comment describing
_Never_valueless_alt to be clear it depends on move construction as well
as move assignment.
Finally, I also observed that _Variant_storage<false, T...>::_M_valid()
was not taking advantage of the __never_valueless<T...>() function to
avoid a runtime check. Only the _Variant_storage<true, T...>::_M_valid()
function was using __never_valueless. That is also fixed.
PR libstdc++/87431
* include/bits/basic_string.h (_Never_valueless_alt): Make partial
specialization also depend on is_nothrow_move_constructible.
* include/std/variant (__detail::__variant::__never_valueless()):
Only true if the variant would have a move assignment operator.
(__detail::__variant::_Variant_storage<false, T...>::_M_valid()):
Check __never_valueless<T...>().
(variant::emplace): Only perform non-throwing move assignments
for never-valueless alternatives if the variant has a move assignment
operator.
* testsuite/20_util/variant/compile.cc: Check that never-valueless
types can be emplaced into non-assignable variants.
* testsuite/20_util/variant/run.cc: Check that never-valueless types
don't get copied when emplaced into non-assignable variants.
From-SVN: r270502
2019-04-23 11:55:33 +02:00
|
|
|
// non-throwing and cheap move construction and move assignment operator,
|
|
|
|
// so that emplacing the type will provide the strong exception-safety
|
|
|
|
// guarantee, by creating and moving a temporary.
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// Whether _Never_valueless_alt<T> is true or not affects the ABI of a
|
|
|
|
// variant using that alternative, so we can't change the value later!
|
|
|
|
|
|
|
|
// True if every alternative in _Types... can be emplaced in a variant
|
|
|
|
// without it becoming valueless. If this is true, variant<_Types...>
|
|
|
|
// can never be valueless, which enables some minor optimizations.
|
2019-03-26 16:00:05 +01:00
|
|
|
template <typename... _Types>
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
constexpr bool __never_valueless()
|
|
|
|
{
|
Fix std::variant regression caused by never-valueless optimization
A regression was introduced by the recent changes to provide the strong
exception safety guarantee for "never valueless" types that have O(1),
non-throwing move assignment. The problematic code is:
else if constexpr (__detail::__variant::_Never_valueless_alt<type>())
{
// This construction might throw:
variant __tmp(in_place_index<_Np>, __il,
std::forward<_Args>(__args)...);
// But _Never_valueless_alt<type> means this won't:
*this = std::move(__tmp);
}
When the variant is not assignable, the assignment is ill-formed, so
should not be attempted. When the variant has a copy assignment operator
but not a move assignment operator, the assignment performs a copy
assignment and that could throw, so should not be attempted.
The solution is to only take that branch when the variant has a move
assignment operator, which is determined by the _Traits::_S_move_assign
constant. When that is false the strong exception safety guarantee is
not possible, and so the __never_valueless function should also depend
on _S_move_assign.
While testing the fixes for this I noticed that the partial
specialization _Never_valueless_alt<basic_string<C,T,A>> incorrectly
assumed that is_nothrow_move_constructible<basic_string<C,T,A>> is
always true, but that's wrong for fully-dynamic COW strings. Fix the
partial specialization, and improve the comment describing
_Never_valueless_alt to be clear it depends on move construction as well
as move assignment.
Finally, I also observed that _Variant_storage<false, T...>::_M_valid()
was not taking advantage of the __never_valueless<T...>() function to
avoid a runtime check. Only the _Variant_storage<true, T...>::_M_valid()
function was using __never_valueless. That is also fixed.
PR libstdc++/87431
* include/bits/basic_string.h (_Never_valueless_alt): Make partial
specialization also depend on is_nothrow_move_constructible.
* include/std/variant (__detail::__variant::__never_valueless()):
Only true if the variant would have a move assignment operator.
(__detail::__variant::_Variant_storage<false, T...>::_M_valid()):
Check __never_valueless<T...>().
(variant::emplace): Only perform non-throwing move assignments
for never-valueless alternatives if the variant has a move assignment
operator.
* testsuite/20_util/variant/compile.cc: Check that never-valueless
types can be emplaced into non-assignable variants.
* testsuite/20_util/variant/run.cc: Check that never-valueless types
don't get copied when emplaced into non-assignable variants.
From-SVN: r270502
2019-04-23 11:55:33 +02:00
|
|
|
return _Traits<_Types...>::_S_move_assign
|
|
|
|
&& (_Never_valueless_alt<_Types>::value && ...);
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
}
|
2019-03-26 16:00:05 +01:00
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
// Defines index and the dtor, possibly trivial.
|
|
|
|
template<bool __trivially_destructible, typename... _Types>
|
|
|
|
struct _Variant_storage;
|
|
|
|
|
2017-01-11 12:23:43 +01:00
|
|
|
template <typename... _Types>
|
2019-04-09 20:50:48 +02:00
|
|
|
using __select_index =
|
|
|
|
typename __select_int::_Select_int_base<sizeof...(_Types),
|
|
|
|
unsigned char,
|
|
|
|
unsigned short>::type::value_type;
|
2017-01-11 12:23:43 +01:00
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
template<typename... _Types>
|
|
|
|
struct _Variant_storage<false, _Types...>
|
|
|
|
{
|
|
|
|
constexpr _Variant_storage() : _M_index(variant_npos) { }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2016-09-22 05:15:58 +02:00
|
|
|
template<size_t _Np, typename... _Args>
|
2016-08-18 22:31:26 +02:00
|
|
|
constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
|
2016-12-06 12:20:13 +01:00
|
|
|
: _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
|
|
|
|
_M_index(_Np)
|
2016-08-18 22:31:26 +02:00
|
|
|
{ }
|
|
|
|
|
2019-05-16 22:30:27 +02:00
|
|
|
void _M_reset()
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
2019-05-16 22:30:27 +02:00
|
|
|
if (!_M_valid()) [[unlikely]]
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::__do_visit<void>([](auto&& __this_mem) mutable
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
2019-05-16 22:30:27 +02:00
|
|
|
std::_Destroy(std::__addressof(__this_mem));
|
2019-03-06 13:56:05 +01:00
|
|
|
}, __variant_cast<_Types...>(*this));
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2016-12-06 12:26:48 +01:00
|
|
|
_M_index = variant_npos;
|
|
|
|
}
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
~_Variant_storage()
|
2016-12-06 12:26:48 +01:00
|
|
|
{ _M_reset(); }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
void*
|
2019-05-10 23:41:19 +02:00
|
|
|
_M_storage() const noexcept
|
2017-06-27 20:19:03 +02:00
|
|
|
{
|
|
|
|
return const_cast<void*>(static_cast<const void*>(
|
|
|
|
std::addressof(_M_u)));
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool
|
|
|
|
_M_valid() const noexcept
|
|
|
|
{
|
2019-06-20 16:17:51 +02:00
|
|
|
if constexpr (__variant::__never_valueless<_Types...>())
|
Fix std::variant regression caused by never-valueless optimization
A regression was introduced by the recent changes to provide the strong
exception safety guarantee for "never valueless" types that have O(1),
non-throwing move assignment. The problematic code is:
else if constexpr (__detail::__variant::_Never_valueless_alt<type>())
{
// This construction might throw:
variant __tmp(in_place_index<_Np>, __il,
std::forward<_Args>(__args)...);
// But _Never_valueless_alt<type> means this won't:
*this = std::move(__tmp);
}
When the variant is not assignable, the assignment is ill-formed, so
should not be attempted. When the variant has a copy assignment operator
but not a move assignment operator, the assignment performs a copy
assignment and that could throw, so should not be attempted.
The solution is to only take that branch when the variant has a move
assignment operator, which is determined by the _Traits::_S_move_assign
constant. When that is false the strong exception safety guarantee is
not possible, and so the __never_valueless function should also depend
on _S_move_assign.
While testing the fixes for this I noticed that the partial
specialization _Never_valueless_alt<basic_string<C,T,A>> incorrectly
assumed that is_nothrow_move_constructible<basic_string<C,T,A>> is
always true, but that's wrong for fully-dynamic COW strings. Fix the
partial specialization, and improve the comment describing
_Never_valueless_alt to be clear it depends on move construction as well
as move assignment.
Finally, I also observed that _Variant_storage<false, T...>::_M_valid()
was not taking advantage of the __never_valueless<T...>() function to
avoid a runtime check. Only the _Variant_storage<true, T...>::_M_valid()
function was using __never_valueless. That is also fixed.
PR libstdc++/87431
* include/bits/basic_string.h (_Never_valueless_alt): Make partial
specialization also depend on is_nothrow_move_constructible.
* include/std/variant (__detail::__variant::__never_valueless()):
Only true if the variant would have a move assignment operator.
(__detail::__variant::_Variant_storage<false, T...>::_M_valid()):
Check __never_valueless<T...>().
(variant::emplace): Only perform non-throwing move assignments
for never-valueless alternatives if the variant has a move assignment
operator.
* testsuite/20_util/variant/compile.cc: Check that never-valueless
types can be emplaced into non-assignable variants.
* testsuite/20_util/variant/run.cc: Check that never-valueless types
don't get copied when emplaced into non-assignable variants.
From-SVN: r270502
2019-04-23 11:55:33 +02:00
|
|
|
return true;
|
2017-06-27 20:19:03 +02:00
|
|
|
return this->_M_index != __index_type(variant_npos);
|
|
|
|
}
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
_Variadic_union<_Types...> _M_u;
|
2017-01-11 12:23:43 +01:00
|
|
|
using __index_type = __select_index<_Types...>;
|
|
|
|
__index_type _M_index;
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
template<typename... _Types>
|
|
|
|
struct _Variant_storage<true, _Types...>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2016-12-06 12:20:13 +01:00
|
|
|
constexpr _Variant_storage() : _M_index(variant_npos) { }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
template<size_t _Np, typename... _Args>
|
|
|
|
constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
|
|
|
|
: _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
|
|
|
|
_M_index(_Np)
|
|
|
|
{ }
|
|
|
|
|
2019-05-10 23:41:19 +02:00
|
|
|
void _M_reset() noexcept
|
2016-12-06 12:26:48 +01:00
|
|
|
{ _M_index = variant_npos; }
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
void*
|
2019-05-10 23:41:19 +02:00
|
|
|
_M_storage() const noexcept
|
2017-06-27 20:19:03 +02:00
|
|
|
{
|
|
|
|
return const_cast<void*>(static_cast<const void*>(
|
|
|
|
std::addressof(_M_u)));
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool
|
|
|
|
_M_valid() const noexcept
|
|
|
|
{
|
2019-06-20 16:17:51 +02:00
|
|
|
if constexpr (__variant::__never_valueless<_Types...>())
|
2018-09-25 16:59:16 +02:00
|
|
|
return true;
|
2017-06-27 20:19:03 +02:00
|
|
|
return this->_M_index != __index_type(variant_npos);
|
|
|
|
}
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
_Variadic_union<_Types...> _M_u;
|
2017-01-11 12:23:43 +01:00
|
|
|
using __index_type = __select_index<_Types...>;
|
|
|
|
__index_type _M_index;
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
2017-06-27 20:19:03 +02:00
|
|
|
using _Variant_storage_alias =
|
2017-07-23 10:41:35 +02:00
|
|
|
_Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-03-28 17:18:49 +01:00
|
|
|
template<typename _Tp, typename _Up>
|
|
|
|
void __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem)
|
|
|
|
{
|
|
|
|
void* __storage = std::addressof(__lhs._M_u);
|
|
|
|
using _Type = remove_reference_t<decltype(__rhs_mem)>;
|
|
|
|
if constexpr (!is_same_v<_Type, __variant_cookie>)
|
|
|
|
::new (__storage)
|
|
|
|
_Type(std::forward<decltype(__rhs_mem)>(__rhs_mem));
|
|
|
|
}
|
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
template<typename... _Types, typename _Tp, typename _Up>
|
|
|
|
void __variant_construct(_Tp&& __lhs, _Up&& __rhs)
|
|
|
|
{
|
|
|
|
__lhs._M_index = __rhs._M_index;
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__variant::__raw_visit([&__lhs](auto&& __rhs_mem) mutable
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
2019-03-28 17:18:49 +01:00
|
|
|
__variant_construct_single(std::forward<_Tp>(__lhs),
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
std::forward<decltype(__rhs_mem)>(__rhs_mem));
|
|
|
|
}, __variant_cast<_Types...>(std::forward<_Up>(__rhs)));
|
2019-03-06 13:56:05 +01:00
|
|
|
}
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
// The following are (Copy|Move) (ctor|assign) layers for forwarding
|
|
|
|
// triviality and handling non-trivial SMF behaviors.
|
|
|
|
|
|
|
|
template<bool, typename... _Types>
|
|
|
|
struct _Copy_ctor_base : _Variant_storage_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Variant_storage_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
_Copy_ctor_base(const _Copy_ctor_base& __rhs)
|
2017-07-23 10:41:35 +02:00
|
|
|
noexcept(_Traits<_Types...>::_S_nothrow_copy_ctor)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-03-06 13:56:05 +01:00
|
|
|
__variant_construct<_Types...>(*this, __rhs);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
_Copy_ctor_base(_Copy_ctor_base&&) = default;
|
|
|
|
_Copy_ctor_base& operator=(const _Copy_ctor_base&) = default;
|
|
|
|
_Copy_ctor_base& operator=(_Copy_ctor_base&&) = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
struct _Copy_ctor_base<true, _Types...> : _Variant_storage_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Variant_storage_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
using _Copy_ctor_alias =
|
2017-07-23 10:41:35 +02:00
|
|
|
_Copy_ctor_base<_Traits<_Types...>::_S_trivial_copy_ctor, _Types...>;
|
2017-06-27 20:19:03 +02:00
|
|
|
|
|
|
|
template<bool, typename... _Types>
|
|
|
|
struct _Move_ctor_base : _Copy_ctor_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Copy_ctor_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
|
|
|
|
|
|
|
_Move_ctor_base(_Move_ctor_base&& __rhs)
|
2017-07-23 10:41:35 +02:00
|
|
|
noexcept(_Traits<_Types...>::_S_nothrow_move_ctor)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant_construct<_Types...>(*this, std::move(__rhs));
|
2019-03-06 13:56:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-28 17:18:49 +01:00
|
|
|
template<typename _Up>
|
|
|
|
void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
|
|
|
|
{
|
|
|
|
this->_M_reset();
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant_construct_single(*this, std::forward<_Up>(__rhs));
|
2019-03-28 17:18:49 +01:00
|
|
|
this->_M_index = __rhs_index;
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-03-28 17:18:49 +01:00
|
|
|
template<typename _Up>
|
|
|
|
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
|
|
|
|
{
|
|
|
|
this->_M_reset();
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant_construct_single(*this, __rhs);
|
2019-03-28 17:18:49 +01:00
|
|
|
this->_M_index = __rhs_index;
|
|
|
|
}
|
2018-08-07 21:13:26 +02:00
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
_Move_ctor_base(const _Move_ctor_base&) = default;
|
|
|
|
_Move_ctor_base& operator=(const _Move_ctor_base&) = default;
|
|
|
|
_Move_ctor_base& operator=(_Move_ctor_base&&) = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
struct _Move_ctor_base<true, _Types...> : _Copy_ctor_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Copy_ctor_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
2018-08-07 21:13:26 +02:00
|
|
|
|
2019-03-28 17:18:49 +01:00
|
|
|
template<typename _Up>
|
|
|
|
void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
|
|
|
|
{
|
|
|
|
this->_M_reset();
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant_construct_single(*this, std::forward<_Up>(__rhs));
|
2019-03-28 17:18:49 +01:00
|
|
|
this->_M_index = __rhs_index;
|
|
|
|
}
|
2019-04-09 20:50:48 +02:00
|
|
|
|
2019-03-28 17:18:49 +01:00
|
|
|
template<typename _Up>
|
|
|
|
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
|
|
|
|
{
|
|
|
|
this->_M_reset();
|
|
|
|
__variant_construct_single(*this, __rhs);
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
this->_M_index = __rhs_index;
|
2019-03-28 17:18:49 +01:00
|
|
|
}
|
2017-06-27 20:19:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
using _Move_ctor_alias =
|
2017-07-23 10:41:35 +02:00
|
|
|
_Move_ctor_base<_Traits<_Types...>::_S_trivial_move_ctor, _Types...>;
|
2017-06-27 20:19:03 +02:00
|
|
|
|
|
|
|
template<bool, typename... _Types>
|
|
|
|
struct _Copy_assign_base : _Move_ctor_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Move_ctor_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
_Copy_assign_base&
|
|
|
|
operator=(const _Copy_assign_base& __rhs)
|
2017-07-23 10:41:35 +02:00
|
|
|
noexcept(_Traits<_Types...>::_S_nothrow_copy_assign)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__variant::__raw_idx_visit(
|
|
|
|
[this](auto&& __rhs_mem, auto __rhs_index) mutable
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
if constexpr (__rhs_index != variant_npos)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
if (this->_M_index == __rhs_index)
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant::__get<__rhs_index>(*this) = __rhs_mem;
|
2019-04-01 15:57:41 +02:00
|
|
|
else
|
|
|
|
{
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
using __rhs_type = __remove_cvref_t<decltype(__rhs_mem)>;
|
|
|
|
if constexpr (is_nothrow_copy_constructible_v<__rhs_type>
|
|
|
|
|| !is_nothrow_move_constructible_v<__rhs_type>)
|
|
|
|
// The standard says this->emplace<__rhs_type>(__rhs_mem)
|
|
|
|
// should be used here, but _M_destructive_copy is
|
|
|
|
// equivalent in this case. Either copy construction
|
|
|
|
// doesn't throw, so _M_destructive_copy gives strong
|
|
|
|
// exception safety guarantee, or both copy construction
|
|
|
|
// and move construction can throw, so emplace only gives
|
|
|
|
// basic exception safety anyway.
|
|
|
|
this->_M_destructive_copy(__rhs_index, __rhs_mem);
|
2019-03-06 13:56:05 +01:00
|
|
|
else
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant_cast<_Types...>(*this)
|
2020-07-02 21:16:39 +02:00
|
|
|
= variant<_Types...>(std::in_place_index<__rhs_index>,
|
|
|
|
__rhs_mem);
|
2019-03-06 13:56:05 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-01 15:57:41 +02:00
|
|
|
else
|
|
|
|
this->_M_reset();
|
|
|
|
}, __variant_cast<_Types...>(__rhs));
|
2016-08-18 22:31:26 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
_Copy_assign_base(const _Copy_assign_base&) = default;
|
|
|
|
_Copy_assign_base(_Copy_assign_base&&) = default;
|
|
|
|
_Copy_assign_base& operator=(_Copy_assign_base&&) = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
struct _Copy_assign_base<true, _Types...> : _Move_ctor_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Move_ctor_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
using _Copy_assign_alias =
|
2019-04-23 14:48:28 +02:00
|
|
|
_Copy_assign_base<_Traits<_Types...>::_S_trivial_copy_assign, _Types...>;
|
2017-06-27 20:19:03 +02:00
|
|
|
|
|
|
|
template<bool, typename... _Types>
|
|
|
|
struct _Move_assign_base : _Copy_assign_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Copy_assign_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
|
|
|
|
|
|
|
_Move_assign_base&
|
|
|
|
operator=(_Move_assign_base&& __rhs)
|
2017-07-23 10:41:35 +02:00
|
|
|
noexcept(_Traits<_Types...>::_S_nothrow_move_assign)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__variant::__raw_idx_visit(
|
|
|
|
[this](auto&& __rhs_mem, auto __rhs_index) mutable
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
if constexpr (__rhs_index != variant_npos)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
if (this->_M_index == __rhs_index)
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant::__get<__rhs_index>(*this) = std::move(__rhs_mem);
|
2019-04-01 15:57:41 +02:00
|
|
|
else
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
__variant_cast<_Types...>(*this)
|
|
|
|
.template emplace<__rhs_index>(std::move(__rhs_mem));
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
2019-03-06 13:56:05 +01:00
|
|
|
else
|
2019-04-01 15:57:41 +02:00
|
|
|
this->_M_reset();
|
|
|
|
}, __variant_cast<_Types...>(__rhs));
|
2016-08-18 22:31:26 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
_Move_assign_base(const _Move_assign_base&) = default;
|
|
|
|
_Move_assign_base(_Move_assign_base&&) = default;
|
|
|
|
_Move_assign_base& operator=(const _Move_assign_base&) = default;
|
|
|
|
};
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
template<typename... _Types>
|
|
|
|
struct _Move_assign_base<true, _Types...> : _Copy_assign_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Copy_assign_alias<_Types...>;
|
|
|
|
using _Base::_Base;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
using _Move_assign_alias =
|
2019-04-09 20:50:48 +02:00
|
|
|
_Move_assign_base<_Traits<_Types...>::_S_trivial_move_assign, _Types...>;
|
2017-06-27 20:19:03 +02:00
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
struct _Variant_base : _Move_assign_alias<_Types...>
|
|
|
|
{
|
|
|
|
using _Base = _Move_assign_alias<_Types...>;
|
|
|
|
|
|
|
|
constexpr
|
|
|
|
_Variant_base()
|
2017-07-23 10:41:35 +02:00
|
|
|
noexcept(_Traits<_Types...>::_S_nothrow_default_ctor)
|
2017-06-27 20:19:03 +02:00
|
|
|
: _Variant_base(in_place_index<0>) { }
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Args>
|
|
|
|
constexpr explicit
|
|
|
|
_Variant_base(in_place_index_t<_Np> __i, _Args&&... __args)
|
|
|
|
: _Base(__i, std::forward<_Args>(__args)...)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
_Variant_base(const _Variant_base&) = default;
|
|
|
|
_Variant_base(_Variant_base&&) = default;
|
|
|
|
_Variant_base& operator=(const _Variant_base&) = default;
|
|
|
|
_Variant_base& operator=(_Variant_base&&) = default;
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// For how many times does _Tp appear in _Tuple?
|
|
|
|
template<typename _Tp, typename _Tuple>
|
|
|
|
struct __tuple_count;
|
|
|
|
|
|
|
|
template<typename _Tp, typename _Tuple>
|
Implement P0607R0 "Inline Variables for Standard Library" for C++17
2017-03-23 Daniel Kruegler <daniel.kruegler@gmail.com>
* include/bits/c++config (_GLIBCXX17_INLINE): Define.
* include/bits/regex_constants.h (All std::regex_constants constants):
Add _GLIBCXX17_INLINE as per P0607R0.
* include/bits/std_mutex.h (defer_lock, try_to_lock, adopt_lock):
Likewise.
* include/bits/stl_pair.h (piecewise_construct): Likewise.
* include/bits/uses_allocator.h (allocator_arg, uses_allocator_v)
(__is_uses_allocator_constructible_v)
(__is_nothrow_uses_allocator_constructible_v): Likewise.
* include/std/chrono (treat_as_floating_point_v): Likewise.
* include/std/functional (is_bind_expression_v, is_placeholder_v):
Likewise.
* include/std/optional (nullopt): Likewise.
* include/std/ratio (ratio_equal_v, ratio_not_equal_v, ratio_less_v)
ratio_less_equal_v, ratio_greater_v, ratio_greater_equal_v): Likewise.
* include/std/system_error (is_error_code_enum_v)
(is_error_condition_enum_v): Likewise.
* include/std/tuple (tuple_size_v, ignore): Likewise.
(ignore): Declare ignore constexpr as per LWG 2773, declare assignment
constexpr as per LWG 2933.
* include/std/type_traits (All variable templates): Add
_GLIBCXX17_INLINE as per P0607R0.
* include/std/variant (variant_size_v, variant_npos, __index_of_v)
(__tuple_count_v, __exactly_once): Likewise.
* testsuite/18_support/headers/new/synopsis.cc
(hardware_destructive_interference_size)
(hardware_constructive_interference_size): Likewise for commented-out
variables.
* testsuite/20_util/tuple/creation_functions/constexpr.cc: Add new
test function for constexpr std::ignore (LWG 2773).
* testsuite/20_util/tuple/creation_functions/constexpr_cpp14.cc: New
test for LWG 2933.
From-SVN: r246423
2017-03-23 20:40:07 +01:00
|
|
|
inline constexpr size_t __tuple_count_v =
|
|
|
|
__tuple_count<_Tp, _Tuple>::value;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
|
|
|
struct __tuple_count<_Tp, tuple<_Types...>>
|
|
|
|
: integral_constant<size_t, 0> { };
|
|
|
|
|
|
|
|
template<typename _Tp, typename _First, typename... _Rest>
|
|
|
|
struct __tuple_count<_Tp, tuple<_First, _Rest...>>
|
|
|
|
: integral_constant<
|
|
|
|
size_t,
|
|
|
|
__tuple_count_v<_Tp, tuple<_Rest...>> + is_same_v<_Tp, _First>> { };
|
|
|
|
|
|
|
|
// TODO: Reuse this in <tuple> ?
|
|
|
|
template<typename _Tp, typename... _Types>
|
Implement P0607R0 "Inline Variables for Standard Library" for C++17
2017-03-23 Daniel Kruegler <daniel.kruegler@gmail.com>
* include/bits/c++config (_GLIBCXX17_INLINE): Define.
* include/bits/regex_constants.h (All std::regex_constants constants):
Add _GLIBCXX17_INLINE as per P0607R0.
* include/bits/std_mutex.h (defer_lock, try_to_lock, adopt_lock):
Likewise.
* include/bits/stl_pair.h (piecewise_construct): Likewise.
* include/bits/uses_allocator.h (allocator_arg, uses_allocator_v)
(__is_uses_allocator_constructible_v)
(__is_nothrow_uses_allocator_constructible_v): Likewise.
* include/std/chrono (treat_as_floating_point_v): Likewise.
* include/std/functional (is_bind_expression_v, is_placeholder_v):
Likewise.
* include/std/optional (nullopt): Likewise.
* include/std/ratio (ratio_equal_v, ratio_not_equal_v, ratio_less_v)
ratio_less_equal_v, ratio_greater_v, ratio_greater_equal_v): Likewise.
* include/std/system_error (is_error_code_enum_v)
(is_error_condition_enum_v): Likewise.
* include/std/tuple (tuple_size_v, ignore): Likewise.
(ignore): Declare ignore constexpr as per LWG 2773, declare assignment
constexpr as per LWG 2933.
* include/std/type_traits (All variable templates): Add
_GLIBCXX17_INLINE as per P0607R0.
* include/std/variant (variant_size_v, variant_npos, __index_of_v)
(__tuple_count_v, __exactly_once): Likewise.
* testsuite/18_support/headers/new/synopsis.cc
(hardware_destructive_interference_size)
(hardware_constructive_interference_size): Likewise for commented-out
variables.
* testsuite/20_util/tuple/creation_functions/constexpr.cc: Add new
test function for constexpr std::ignore (LWG 2773).
* testsuite/20_util/tuple/creation_functions/constexpr_cpp14.cc: New
test for LWG 2933.
From-SVN: r246423
2017-03-23 20:40:07 +01:00
|
|
|
inline constexpr bool __exactly_once =
|
|
|
|
__tuple_count_v<_Tp, tuple<_Types...>> == 1;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-05-16 22:30:35 +02:00
|
|
|
// Helper used to check for valid conversions that don't involve narrowing.
|
|
|
|
template<typename _Ti> struct _Arr { _Ti _M_x[1]; };
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2020-06-23 11:24:49 +02:00
|
|
|
// "Build an imaginary function FUN(Ti) for each alternative type Ti"
|
|
|
|
template<size_t _Ind, typename _Tp, typename _Ti, typename = void>
|
2019-05-16 22:30:35 +02:00
|
|
|
struct _Build_FUN
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-05-16 22:30:35 +02:00
|
|
|
// This function means 'using _Build_FUN<I, T, Ti>::_S_fun;' is valid,
|
|
|
|
// but only static functions will be considered in the call below.
|
|
|
|
void _S_fun();
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2020-06-23 11:24:49 +02:00
|
|
|
// "... for which Ti x[] = {std::forward<T>(t)}; is well-formed."
|
2019-05-16 22:30:35 +02:00
|
|
|
template<size_t _Ind, typename _Tp, typename _Ti>
|
2020-06-23 11:24:49 +02:00
|
|
|
struct _Build_FUN<_Ind, _Tp, _Ti,
|
2019-05-16 22:30:35 +02:00
|
|
|
void_t<decltype(_Arr<_Ti>{{std::declval<_Tp>()}})>>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-05-16 22:30:35 +02:00
|
|
|
// This is the FUN function for type _Ti, with index _Ind
|
|
|
|
static integral_constant<size_t, _Ind> _S_fun(_Ti);
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2019-05-16 22:30:35 +02:00
|
|
|
template<typename _Tp, typename _Variant,
|
|
|
|
typename = make_index_sequence<variant_size_v<_Variant>>>
|
|
|
|
struct _Build_FUNs;
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Ti, size_t... _Ind>
|
|
|
|
struct _Build_FUNs<_Tp, variant<_Ti...>, index_sequence<_Ind...>>
|
|
|
|
: _Build_FUN<_Ind, _Tp, _Ti>...
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-05-16 22:30:35 +02:00
|
|
|
using _Build_FUN<_Ind, _Tp, _Ti>::_S_fun...;
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2019-05-16 22:30:35 +02:00
|
|
|
// The index j of the overload FUN(Tj) selected by overload resolution
|
|
|
|
// for FUN(std::forward<_Tp>(t))
|
|
|
|
template<typename _Tp, typename _Variant>
|
|
|
|
using _FUN_type
|
|
|
|
= decltype(_Build_FUNs<_Tp, _Variant>::_S_fun(std::declval<_Tp>()));
|
|
|
|
|
|
|
|
// The index selected for FUN(std::forward<T>(t)), or variant_npos if none.
|
|
|
|
template<typename _Tp, typename _Variant, typename = void>
|
|
|
|
struct __accepted_index
|
|
|
|
: integral_constant<size_t, variant_npos>
|
|
|
|
{ };
|
|
|
|
|
|
|
|
template<typename _Tp, typename _Variant>
|
|
|
|
struct __accepted_index<_Tp, _Variant, void_t<_FUN_type<_Tp, _Variant>>>
|
|
|
|
: _FUN_type<_Tp, _Variant>
|
|
|
|
{ };
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
// Returns the raw storage for __v.
|
|
|
|
template<typename _Variant>
|
2019-05-10 23:41:19 +02:00
|
|
|
void* __get_storage(_Variant&& __v) noexcept
|
2016-08-18 22:31:26 +02:00
|
|
|
{ return __v._M_storage(); }
|
|
|
|
|
2019-03-26 16:00:05 +01:00
|
|
|
template <typename _Maybe_variant_cookie, typename _Variant>
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
struct _Extra_visit_slot_needed
|
|
|
|
{
|
|
|
|
template <typename> struct _Variant_never_valueless;
|
2019-03-26 16:00:05 +01:00
|
|
|
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
template <typename... _Types>
|
|
|
|
struct _Variant_never_valueless<variant<_Types...>>
|
2019-06-20 16:17:51 +02:00
|
|
|
: bool_constant<__variant::__never_valueless<_Types...>()> {};
|
2019-03-26 16:00:05 +01:00
|
|
|
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
static constexpr bool value =
|
|
|
|
(is_same_v<_Maybe_variant_cookie, __variant_cookie>
|
|
|
|
|| is_same_v<_Maybe_variant_cookie, __variant_idx_cookie>)
|
|
|
|
&& !_Variant_never_valueless<__remove_cvref_t<_Variant>>::value;
|
|
|
|
};
|
2019-03-26 16:00:05 +01:00
|
|
|
|
2019-04-09 20:50:48 +02:00
|
|
|
// Used for storing a multi-dimensional vtable.
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename _Tp, size_t... _Dimensions>
|
2019-04-09 20:50:48 +02:00
|
|
|
struct _Multi_array;
|
|
|
|
|
|
|
|
// Partial specialization with rank zero, stores a single _Tp element.
|
|
|
|
template<typename _Tp>
|
|
|
|
struct _Multi_array<_Tp>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename>
|
|
|
|
struct __untag_result
|
|
|
|
: false_type
|
|
|
|
{ using element_type = _Tp; };
|
|
|
|
|
|
|
|
template <typename... _Args>
|
|
|
|
struct __untag_result<const void(*)(_Args...)>
|
|
|
|
: false_type
|
|
|
|
{ using element_type = void(*)(_Args...); };
|
|
|
|
|
|
|
|
template <typename... _Args>
|
|
|
|
struct __untag_result<__variant_cookie(*)(_Args...)>
|
|
|
|
: false_type
|
|
|
|
{ using element_type = void(*)(_Args...); };
|
|
|
|
|
|
|
|
template <typename... _Args>
|
|
|
|
struct __untag_result<__variant_idx_cookie(*)(_Args...)>
|
|
|
|
: false_type
|
|
|
|
{ using element_type = void(*)(_Args...); };
|
|
|
|
|
|
|
|
template <typename _Res, typename... _Args>
|
|
|
|
struct __untag_result<__deduce_visit_result<_Res>(*)(_Args...)>
|
|
|
|
: true_type
|
|
|
|
{ using element_type = _Res(*)(_Args...); };
|
|
|
|
|
|
|
|
using __result_is_deduced = __untag_result<_Tp>;
|
|
|
|
|
|
|
|
constexpr const typename __untag_result<_Tp>::element_type&
|
2016-08-18 22:31:26 +02:00
|
|
|
_M_access() const
|
|
|
|
{ return _M_data; }
|
|
|
|
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
typename __untag_result<_Tp>::element_type _M_data;
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2019-04-09 20:50:48 +02:00
|
|
|
// Partial specialization with rank >= 1.
|
2019-03-06 13:56:05 +01:00
|
|
|
template<typename _Ret,
|
|
|
|
typename _Visitor,
|
|
|
|
typename... _Variants,
|
|
|
|
size_t __first, size_t... __rest>
|
|
|
|
struct _Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-03-26 16:00:05 +01:00
|
|
|
static constexpr size_t __index =
|
|
|
|
sizeof...(_Variants) - sizeof...(__rest) - 1;
|
2019-04-09 20:50:48 +02:00
|
|
|
|
2019-03-26 16:00:05 +01:00
|
|
|
using _Variant = typename _Nth_type<__index, _Variants...>::type;
|
2019-04-09 20:50:48 +02:00
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
static constexpr int __do_cookie =
|
2019-03-26 16:00:05 +01:00
|
|
|
_Extra_visit_slot_needed<_Ret, _Variant>::value ? 1 : 0;
|
2019-04-09 20:50:48 +02:00
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
using _Tp = _Ret(*)(_Visitor, _Variants...);
|
2019-04-09 20:50:48 +02:00
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename... _Args>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
constexpr decltype(auto)
|
2016-08-18 22:31:26 +02:00
|
|
|
_M_access(size_t __first_index, _Args... __rest_indices) const
|
2019-04-09 20:50:48 +02:00
|
|
|
{
|
|
|
|
return _M_arr[__first_index + __do_cookie]
|
|
|
|
._M_access(__rest_indices...);
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
_Multi_array<_Tp, __rest...> _M_arr[__first + __do_cookie];
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// Creates a multi-dimensional vtable recursively.
|
|
|
|
//
|
|
|
|
// For example,
|
|
|
|
// visit([](auto, auto){},
|
2016-12-06 12:28:09 +01:00
|
|
|
// variant<int, char>(), // typedef'ed as V1
|
|
|
|
// variant<float, double, long double>()) // typedef'ed as V2
|
2016-08-18 22:31:26 +02:00
|
|
|
// will trigger instantiations of:
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 2, 3>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<0>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<0, 0>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<0, 1>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<0, 2>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<1>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<1, 0>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<1, 1>>
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
|
2016-12-06 12:28:09 +01:00
|
|
|
// tuple<V1&&, V2&&>, std::index_sequence<1, 2>>
|
2016-08-18 22:31:26 +02:00
|
|
|
// The returned multi-dimensional vtable can be fast accessed by the visitor
|
|
|
|
// using index calculation.
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename _Array_type, typename _Index_seq>
|
2016-08-18 22:31:26 +02:00
|
|
|
struct __gen_vtable_impl;
|
|
|
|
|
2019-04-09 20:50:48 +02:00
|
|
|
// Defines the _S_apply() member that returns a _Multi_array populated
|
|
|
|
// with function pointers that perform the visitation expressions e(m)
|
|
|
|
// for each valid pack of indexes into the variant types _Variants.
|
|
|
|
//
|
|
|
|
// This partial specialization builds up the index sequences by recursively
|
|
|
|
// calling _S_apply() on the next specialization of __gen_vtable_impl.
|
|
|
|
// The base case of the recursion defines the actual function pointers.
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename _Result_type, typename _Visitor, size_t... __dimensions,
|
2016-12-06 12:28:09 +01:00
|
|
|
typename... _Variants, size_t... __indices>
|
|
|
|
struct __gen_vtable_impl<
|
2017-01-05 04:18:17 +01:00
|
|
|
_Multi_array<_Result_type (*)(_Visitor, _Variants...), __dimensions...>,
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
std::index_sequence<__indices...>>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2016-12-06 12:28:09 +01:00
|
|
|
using _Next =
|
|
|
|
remove_reference_t<typename _Nth_type<sizeof...(__indices),
|
|
|
|
_Variants...>::type>;
|
|
|
|
using _Array_type =
|
2017-01-05 04:18:17 +01:00
|
|
|
_Multi_array<_Result_type (*)(_Visitor, _Variants...),
|
|
|
|
__dimensions...>;
|
2016-12-06 12:28:09 +01:00
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
static constexpr _Array_type
|
|
|
|
_S_apply()
|
|
|
|
{
|
|
|
|
_Array_type __vtable{};
|
|
|
|
_S_apply_all_alts(
|
2016-12-06 12:28:09 +01:00
|
|
|
__vtable, make_index_sequence<variant_size_v<_Next>>());
|
2016-08-18 22:31:26 +02:00
|
|
|
return __vtable;
|
|
|
|
}
|
|
|
|
|
2016-12-06 12:28:09 +01:00
|
|
|
template<size_t... __var_indices>
|
2016-08-18 22:31:26 +02:00
|
|
|
static constexpr void
|
2016-12-06 12:28:09 +01:00
|
|
|
_S_apply_all_alts(_Array_type& __vtable,
|
|
|
|
std::index_sequence<__var_indices...>)
|
|
|
|
{
|
2019-03-26 16:00:05 +01:00
|
|
|
if constexpr (_Extra_visit_slot_needed<_Result_type, _Next>::value)
|
2019-03-06 13:56:05 +01:00
|
|
|
(_S_apply_single_alt<true, __var_indices>(
|
|
|
|
__vtable._M_arr[__var_indices + 1],
|
|
|
|
&(__vtable._M_arr[0])), ...);
|
|
|
|
else
|
|
|
|
(_S_apply_single_alt<false, __var_indices>(
|
|
|
|
__vtable._M_arr[__var_indices]), ...);
|
2016-12-06 12:28:09 +01:00
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
template<bool __do_cookie, size_t __index, typename _Tp>
|
2016-08-18 22:31:26 +02:00
|
|
|
static constexpr void
|
2019-03-06 13:56:05 +01:00
|
|
|
_S_apply_single_alt(_Tp& __element, _Tp* __cookie_element = nullptr)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-03-06 13:56:05 +01:00
|
|
|
if constexpr (__do_cookie)
|
|
|
|
{
|
|
|
|
__element = __gen_vtable_impl<
|
|
|
|
_Tp,
|
|
|
|
std::index_sequence<__indices..., __index>>::_S_apply();
|
|
|
|
*__cookie_element = __gen_vtable_impl<
|
|
|
|
_Tp,
|
|
|
|
std::index_sequence<__indices..., variant_npos>>::_S_apply();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
__element = __gen_vtable_impl<
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
remove_reference_t<decltype(__element)>,
|
2019-03-06 13:56:05 +01:00
|
|
|
std::index_sequence<__indices..., __index>>::_S_apply();
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-04-09 20:50:48 +02:00
|
|
|
// This partial specialization is the base case for the recursion.
|
|
|
|
// It populates a _Multi_array element with the address of a function
|
|
|
|
// that invokes the visitor with the alternatives specified by __indices.
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename _Result_type, typename _Visitor, typename... _Variants,
|
2016-12-06 12:28:09 +01:00
|
|
|
size_t... __indices>
|
2016-08-18 22:31:26 +02:00
|
|
|
struct __gen_vtable_impl<
|
2016-12-06 12:28:09 +01:00
|
|
|
_Multi_array<_Result_type (*)(_Visitor, _Variants...)>,
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
std::index_sequence<__indices...>>
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
using _Array_type =
|
2019-04-09 20:50:48 +02:00
|
|
|
_Multi_array<_Result_type (*)(_Visitor, _Variants...)>;
|
2016-12-06 12:28:09 +01:00
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
template<size_t __index, typename _Variant>
|
|
|
|
static constexpr decltype(auto)
|
2019-04-23 11:55:28 +02:00
|
|
|
__element_by_index_or_cookie(_Variant&& __var) noexcept
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
|
|
|
if constexpr (__index != variant_npos)
|
|
|
|
return __variant::__get<__index>(std::forward<_Variant>(__var));
|
|
|
|
else
|
|
|
|
return __variant_cookie{};
|
|
|
|
}
|
|
|
|
|
2018-10-02 16:00:50 +02:00
|
|
|
static constexpr decltype(auto)
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__visit_invoke(_Visitor&& __visitor, _Variants... __vars)
|
2016-12-06 12:28:09 +01:00
|
|
|
{
|
2019-04-09 20:50:48 +02:00
|
|
|
if constexpr (is_same_v<_Result_type, __variant_idx_cookie>)
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
// For raw visitation using indices, pass the indices to the visitor
|
|
|
|
// and discard the return value:
|
|
|
|
std::__invoke(std::forward<_Visitor>(__visitor),
|
2019-04-09 20:50:48 +02:00
|
|
|
__element_by_index_or_cookie<__indices>(
|
|
|
|
std::forward<_Variants>(__vars))...,
|
|
|
|
integral_constant<size_t, __indices>()...);
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
else if constexpr (is_same_v<_Result_type, __variant_cookie>)
|
|
|
|
// For raw visitation without indices, and discard the return value:
|
|
|
|
std::__invoke(std::forward<_Visitor>(__visitor),
|
2019-04-09 20:50:48 +02:00
|
|
|
__element_by_index_or_cookie<__indices>(
|
|
|
|
std::forward<_Variants>(__vars))...);
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
else if constexpr (_Array_type::__result_is_deduced::value)
|
|
|
|
// For the usual std::visit case deduce the return value:
|
2019-04-01 15:57:41 +02:00
|
|
|
return std::__invoke(std::forward<_Visitor>(__visitor),
|
2019-04-09 20:50:48 +02:00
|
|
|
__element_by_index_or_cookie<__indices>(
|
|
|
|
std::forward<_Variants>(__vars))...);
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
else // for std::visit<R> use INVOKE<R>
|
|
|
|
return std::__invoke_r<_Result_type>(
|
|
|
|
std::forward<_Visitor>(__visitor),
|
|
|
|
__variant::__get<__indices>(std::forward<_Variants>(__vars))...);
|
2019-04-08 21:45:48 +02:00
|
|
|
}
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
static constexpr auto
|
|
|
|
_S_apply()
|
2016-12-06 12:28:09 +01:00
|
|
|
{ return _Array_type{&__visit_invoke}; }
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename _Result_type, typename _Visitor, typename... _Variants>
|
2016-08-18 22:31:26 +02:00
|
|
|
struct __gen_vtable
|
|
|
|
{
|
|
|
|
using _Array_type =
|
2019-04-09 20:50:48 +02:00
|
|
|
_Multi_array<_Result_type (*)(_Visitor, _Variants...),
|
2019-03-26 13:41:59 +01:00
|
|
|
variant_size_v<remove_reference_t<_Variants>>...>;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-04-09 20:50:48 +02:00
|
|
|
static constexpr _Array_type _S_vtable
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
= __gen_vtable_impl<_Array_type, std::index_sequence<>>::_S_apply();
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
2016-12-06 12:26:48 +01:00
|
|
|
template<size_t _Np, typename _Tp>
|
|
|
|
struct _Base_dedup : public _Tp { };
|
|
|
|
|
|
|
|
template<typename _Variant, typename __indices>
|
|
|
|
struct _Variant_hash_base;
|
|
|
|
|
|
|
|
template<typename... _Types, size_t... __indices>
|
|
|
|
struct _Variant_hash_base<variant<_Types...>,
|
|
|
|
std::index_sequence<__indices...>>
|
|
|
|
: _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { };
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
} // namespace __variant
|
|
|
|
} // namespace __detail
|
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
template<size_t _Np, typename _Variant, typename... _Args>
|
|
|
|
void __variant_construct_by_index(_Variant& __v, _Args&&... __args)
|
|
|
|
{
|
|
|
|
__v._M_index = _Np;
|
|
|
|
auto&& __storage = __detail::__variant::__get<_Np>(__v);
|
|
|
|
::new ((void*)std::addressof(__storage))
|
|
|
|
remove_reference_t<decltype(__storage)>
|
|
|
|
(std::forward<_Args>(__args)...);
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr bool
|
|
|
|
holds_alternative(const variant<_Types...>& __v) noexcept
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2016-08-18 22:31:26 +02:00
|
|
|
return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr _Tp& get(variant<_Types...>& __v)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2019-06-12 16:52:09 +02:00
|
|
|
static_assert(!is_void_v<_Tp>, "_Tp must not be void");
|
2018-03-09 02:10:02 +01:00
|
|
|
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr _Tp&& get(variant<_Types...>&& __v)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2019-06-12 16:52:09 +02:00
|
|
|
static_assert(!is_void_v<_Tp>, "_Tp must not be void");
|
2018-03-09 02:10:02 +01:00
|
|
|
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(
|
2016-08-18 22:31:26 +02:00
|
|
|
std::move(__v));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr const _Tp& get(const variant<_Types...>& __v)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2019-06-12 16:52:09 +02:00
|
|
|
static_assert(!is_void_v<_Tp>, "_Tp must not be void");
|
2018-03-09 02:10:02 +01:00
|
|
|
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr const _Tp&& get(const variant<_Types...>&& __v)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2019-06-12 16:52:09 +02:00
|
|
|
static_assert(!is_void_v<_Tp>, "_Tp must not be void");
|
2018-03-09 02:10:02 +01:00
|
|
|
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(
|
2016-08-18 22:31:26 +02:00
|
|
|
std::move(__v));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr add_pointer_t<variant_alternative_t<_Np, variant<_Types...>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
get_if(variant<_Types...>* __ptr) noexcept
|
|
|
|
{
|
|
|
|
using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>;
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
|
|
|
static_assert(!is_void_v<_Alternative_type>, "_Tp must not be void");
|
2016-08-18 22:31:26 +02:00
|
|
|
if (__ptr && __ptr->index() == _Np)
|
2019-03-06 13:56:05 +01:00
|
|
|
return std::addressof(__detail::__variant::__get<_Np>(*__ptr));
|
2016-08-18 22:31:26 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr
|
2016-12-06 12:20:13 +01:00
|
|
|
add_pointer_t<const variant_alternative_t<_Np, variant<_Types...>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
get_if(const variant<_Types...>* __ptr) noexcept
|
|
|
|
{
|
|
|
|
using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>;
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
|
|
|
static_assert(!is_void_v<_Alternative_type>, "_Tp must not be void");
|
2016-08-18 22:31:26 +02:00
|
|
|
if (__ptr && __ptr->index() == _Np)
|
2019-03-06 13:56:05 +01:00
|
|
|
return std::addressof(__detail::__variant::__get<_Np>(*__ptr));
|
2016-08-18 22:31:26 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr add_pointer_t<_Tp>
|
2016-12-06 12:20:13 +01:00
|
|
|
get_if(variant<_Types...>* __ptr) noexcept
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2019-06-12 16:52:09 +02:00
|
|
|
static_assert(!is_void_v<_Tp>, "_Tp must not be void");
|
2018-03-09 02:10:02 +01:00
|
|
|
return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>(
|
|
|
|
__ptr);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Types>
|
2018-10-02 16:00:50 +02:00
|
|
|
constexpr add_pointer_t<const _Tp>
|
2019-04-23 11:55:28 +02:00
|
|
|
get_if(const variant<_Types...>* __ptr) noexcept
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
|
2019-05-17 16:36:37 +02:00
|
|
|
"T must occur exactly once in alternatives");
|
2019-06-12 16:52:09 +02:00
|
|
|
static_assert(!is_void_v<_Tp>, "_Tp must not be void");
|
2018-03-09 02:10:02 +01:00
|
|
|
return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>(
|
|
|
|
__ptr);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
2017-02-15 10:01:06 +01:00
|
|
|
struct monostate { };
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2017-02-15 10:01:06 +01:00
|
|
|
#define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP, __NAME) \
|
|
|
|
template<typename... _Types> \
|
|
|
|
constexpr bool operator __OP(const variant<_Types...>& __lhs, \
|
|
|
|
const variant<_Types...>& __rhs) \
|
|
|
|
{ \
|
2019-03-06 13:56:05 +01:00
|
|
|
bool __ret = true; \
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__detail::__variant::__raw_idx_visit( \
|
|
|
|
[&__ret, &__lhs] (auto&& __rhs_mem, auto __rhs_index) mutable \
|
2019-03-06 13:56:05 +01:00
|
|
|
{ \
|
2019-04-01 15:57:41 +02:00
|
|
|
if constexpr (__rhs_index != variant_npos) \
|
|
|
|
{ \
|
|
|
|
if (__lhs.index() == __rhs_index) \
|
|
|
|
{ \
|
|
|
|
auto& __this_mem = std::get<__rhs_index>(__lhs); \
|
|
|
|
__ret = __this_mem __OP __rhs_mem; \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
__ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
__ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \
|
|
|
|
}, __rhs); \
|
2019-03-06 13:56:05 +01:00
|
|
|
return __ret; \
|
2020-02-21 13:02:15 +01:00
|
|
|
}
|
2017-02-15 10:01:06 +01:00
|
|
|
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(<, less)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(<=, less_equal)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(==, equal)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(!=, not_equal)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(>=, greater_equal)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(>, greater)
|
|
|
|
|
|
|
|
#undef _VARIANT_RELATION_FUNCTION_TEMPLATE
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2020-02-21 13:02:15 +01:00
|
|
|
constexpr bool operator==(monostate, monostate) noexcept { return true; }
|
|
|
|
|
|
|
|
#ifdef __cpp_lib_three_way_comparison
|
|
|
|
template<typename... _Types>
|
|
|
|
requires (three_way_comparable<_Types> && ...)
|
|
|
|
constexpr
|
|
|
|
common_comparison_category_t<compare_three_way_result_t<_Types>...>
|
|
|
|
operator<=>(const variant<_Types...>& __v, const variant<_Types...>& __w)
|
|
|
|
{
|
|
|
|
common_comparison_category_t<compare_three_way_result_t<_Types>...> __ret
|
|
|
|
= strong_ordering::equal;
|
|
|
|
|
|
|
|
__detail::__variant::__raw_idx_visit(
|
|
|
|
[&__ret, &__v] (auto&& __w_mem, auto __w_index) mutable
|
|
|
|
{
|
|
|
|
if constexpr (__w_index != variant_npos)
|
|
|
|
{
|
|
|
|
if (__v.index() == __w_index)
|
|
|
|
{
|
|
|
|
auto& __this_mem = std::get<__w_index>(__v);
|
|
|
|
__ret = __this_mem <=> __w_mem;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
__ret = (__v.index() + 1) <=> (__w_index + 1);
|
|
|
|
}, __w);
|
|
|
|
return __ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr strong_ordering
|
|
|
|
operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; }
|
|
|
|
#else
|
|
|
|
constexpr bool operator!=(monostate, monostate) noexcept { return false; }
|
|
|
|
constexpr bool operator<(monostate, monostate) noexcept { return false; }
|
|
|
|
constexpr bool operator>(monostate, monostate) noexcept { return false; }
|
|
|
|
constexpr bool operator<=(monostate, monostate) noexcept { return true; }
|
|
|
|
constexpr bool operator>=(monostate, monostate) noexcept { return true; }
|
|
|
|
#endif
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename _Visitor, typename... _Variants>
|
2016-12-06 12:28:09 +01:00
|
|
|
constexpr decltype(auto) visit(_Visitor&&, _Variants&&...);
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename... _Types>
|
2016-12-06 12:26:48 +01:00
|
|
|
inline enable_if_t<(is_move_constructible_v<_Types> && ...)
|
|
|
|
&& (is_swappable_v<_Types> && ...)>
|
Implement LWG 2766,
Swapping non-swappable types and LWG 2749,
swappable traits for variants.
* include/bits/move.h (swap(_Tp&, _Tp&)): Constrain
with __is_tuple_like.
* include/bits/stl_pair.h (swap(pair<_T1, _T2>&, pair<_T1, _T2>&)):
Add a deleted overload.
* include/bits/unique_ptr.h
(swap(unique_ptr<_Tp, _Dp>&, unique_ptr<_Tp, _Dp>&)): Likewise.
* include/std/array
(swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&)): Likewise.
* include/std/optional
(swap(optional<_Tp>&, optional<_Tp>&)): Likewise.
* include/std/tuple (__is_tuple_like_impl, __is_tuple_like):
Move to type_traits.
(swap(tuple<_Elements...>&, tuple<_Elements...>&)): Add a deleted
overload.
* include/std/type_traits (__is_tuple_like_impl, __is_tuple_like):
New.
(swap(_Tp&, _Tp&)): Constrain with __is_tuple_like.
* include/std/utility (__is_tuple_like_impl): Move to type_traits.
* include/std/variant
(swap(variant<_Types...>&, variant<_Types...>&)):
Add a deleted overload.
* testsuite/20_util/optional/swap/2.cc: Add tests for disabled
swaps.
* testsuite/20_util/pair/swap_cxx17.cc: New.
* testsuite/20_util/tuple/swap_cxx17.cc: Likewise.
* testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc:
Likewise.
* testsuite/20_util/variant/compile.cc: Add tests for disabled
swaps.
* testsuite/23_containers/array/specialized_algorithms/swap_cxx17.cc:
New.
* testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust.
* testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc:
Likewise.
From-SVN: r243120
2016-12-01 17:23:21 +01:00
|
|
|
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
|
|
|
|
noexcept(noexcept(__lhs.swap(__rhs)))
|
2016-08-18 22:31:26 +02:00
|
|
|
{ __lhs.swap(__rhs); }
|
|
|
|
|
Implement LWG 2766,
Swapping non-swappable types and LWG 2749,
swappable traits for variants.
* include/bits/move.h (swap(_Tp&, _Tp&)): Constrain
with __is_tuple_like.
* include/bits/stl_pair.h (swap(pair<_T1, _T2>&, pair<_T1, _T2>&)):
Add a deleted overload.
* include/bits/unique_ptr.h
(swap(unique_ptr<_Tp, _Dp>&, unique_ptr<_Tp, _Dp>&)): Likewise.
* include/std/array
(swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&)): Likewise.
* include/std/optional
(swap(optional<_Tp>&, optional<_Tp>&)): Likewise.
* include/std/tuple (__is_tuple_like_impl, __is_tuple_like):
Move to type_traits.
(swap(tuple<_Elements...>&, tuple<_Elements...>&)): Add a deleted
overload.
* include/std/type_traits (__is_tuple_like_impl, __is_tuple_like):
New.
(swap(_Tp&, _Tp&)): Constrain with __is_tuple_like.
* include/std/utility (__is_tuple_like_impl): Move to type_traits.
* include/std/variant
(swap(variant<_Types...>&, variant<_Types...>&)):
Add a deleted overload.
* testsuite/20_util/optional/swap/2.cc: Add tests for disabled
swaps.
* testsuite/20_util/pair/swap_cxx17.cc: New.
* testsuite/20_util/tuple/swap_cxx17.cc: Likewise.
* testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc:
Likewise.
* testsuite/20_util/variant/compile.cc: Add tests for disabled
swaps.
* testsuite/23_containers/array/specialized_algorithms/swap_cxx17.cc:
New.
* testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust.
* testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc:
Likewise.
From-SVN: r243120
2016-12-01 17:23:21 +01:00
|
|
|
template<typename... _Types>
|
2017-01-06 16:27:01 +01:00
|
|
|
enable_if_t<!((is_move_constructible_v<_Types> && ...)
|
|
|
|
&& (is_swappable_v<_Types> && ...))>
|
Implement LWG 2766,
Swapping non-swappable types and LWG 2749,
swappable traits for variants.
* include/bits/move.h (swap(_Tp&, _Tp&)): Constrain
with __is_tuple_like.
* include/bits/stl_pair.h (swap(pair<_T1, _T2>&, pair<_T1, _T2>&)):
Add a deleted overload.
* include/bits/unique_ptr.h
(swap(unique_ptr<_Tp, _Dp>&, unique_ptr<_Tp, _Dp>&)): Likewise.
* include/std/array
(swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&)): Likewise.
* include/std/optional
(swap(optional<_Tp>&, optional<_Tp>&)): Likewise.
* include/std/tuple (__is_tuple_like_impl, __is_tuple_like):
Move to type_traits.
(swap(tuple<_Elements...>&, tuple<_Elements...>&)): Add a deleted
overload.
* include/std/type_traits (__is_tuple_like_impl, __is_tuple_like):
New.
(swap(_Tp&, _Tp&)): Constrain with __is_tuple_like.
* include/std/utility (__is_tuple_like_impl): Move to type_traits.
* include/std/variant
(swap(variant<_Types...>&, variant<_Types...>&)):
Add a deleted overload.
* testsuite/20_util/optional/swap/2.cc: Add tests for disabled
swaps.
* testsuite/20_util/pair/swap_cxx17.cc: New.
* testsuite/20_util/tuple/swap_cxx17.cc: Likewise.
* testsuite/20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc:
Likewise.
* testsuite/20_util/variant/compile.cc: Add tests for disabled
swaps.
* testsuite/23_containers/array/specialized_algorithms/swap_cxx17.cc:
New.
* testsuite/23_containers/array/tuple_interface/get_neg.cc: Adjust.
* testsuite/23_containers/array/tuple_interface/tuple_element_neg.cc:
Likewise.
From-SVN: r243120
2016-12-01 17:23:21 +01:00
|
|
|
swap(variant<_Types...>&, variant<_Types...>&) = delete;
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
class bad_variant_access : public exception
|
|
|
|
{
|
|
|
|
public:
|
2019-05-17 16:36:37 +02:00
|
|
|
bad_variant_access() noexcept { }
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
const char* what() const noexcept override
|
|
|
|
{ return _M_reason; }
|
|
|
|
|
|
|
|
private:
|
2019-05-17 16:36:37 +02:00
|
|
|
bad_variant_access(const char* __reason) noexcept : _M_reason(__reason) { }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-05-17 16:36:37 +02:00
|
|
|
// Must point to a string with static storage duration:
|
|
|
|
const char* _M_reason = "bad variant access";
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
friend void __throw_bad_variant_access(const char* __what);
|
|
|
|
};
|
|
|
|
|
2019-05-17 16:36:37 +02:00
|
|
|
// Must only be called with a string literal
|
2016-08-18 22:31:26 +02:00
|
|
|
inline void
|
|
|
|
__throw_bad_variant_access(const char* __what)
|
|
|
|
{ _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); }
|
|
|
|
|
2019-05-17 16:36:37 +02:00
|
|
|
inline void
|
|
|
|
__throw_bad_variant_access(bool __valueless)
|
|
|
|
{
|
|
|
|
if (__valueless) [[__unlikely__]]
|
|
|
|
__throw_bad_variant_access("std::get: variant is valueless");
|
|
|
|
else
|
|
|
|
__throw_bad_variant_access("std::get: wrong index for variant");
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename... _Types>
|
|
|
|
class variant
|
|
|
|
: private __detail::__variant::_Variant_base<_Types...>,
|
|
|
|
private _Enable_default_constructor<
|
2017-07-23 10:41:35 +02:00
|
|
|
__detail::__variant::_Traits<_Types...>::_S_default_ctor,
|
2017-06-27 20:19:03 +02:00
|
|
|
variant<_Types...>>,
|
2016-08-18 22:31:26 +02:00
|
|
|
private _Enable_copy_move<
|
2017-07-23 10:41:35 +02:00
|
|
|
__detail::__variant::_Traits<_Types...>::_S_copy_ctor,
|
|
|
|
__detail::__variant::_Traits<_Types...>::_S_copy_assign,
|
|
|
|
__detail::__variant::_Traits<_Types...>::_S_move_ctor,
|
|
|
|
__detail::__variant::_Traits<_Types...>::_S_move_assign,
|
2016-08-18 22:31:26 +02:00
|
|
|
variant<_Types...>>
|
|
|
|
{
|
|
|
|
private:
|
2019-03-06 13:56:05 +01:00
|
|
|
template <typename... _UTypes, typename _Tp>
|
|
|
|
friend decltype(auto) __variant_cast(_Tp&&);
|
|
|
|
template<size_t _Np, typename _Variant, typename... _Args>
|
|
|
|
friend void __variant_construct_by_index(_Variant& __v,
|
|
|
|
_Args&&... __args);
|
|
|
|
|
2016-11-15 18:26:59 +01:00
|
|
|
static_assert(sizeof...(_Types) > 0,
|
|
|
|
"variant must have at least one alternative");
|
|
|
|
static_assert(!(std::is_reference_v<_Types> || ...),
|
|
|
|
"variant must have no reference alternative");
|
|
|
|
static_assert(!(std::is_void_v<_Types> || ...),
|
|
|
|
"variant must have no void alternative");
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
using _Base = __detail::__variant::_Variant_base<_Types...>;
|
|
|
|
using _Default_ctor_enabler =
|
2017-07-23 10:41:35 +02:00
|
|
|
_Enable_default_constructor<
|
|
|
|
__detail::__variant::_Traits<_Types...>::_S_default_ctor,
|
|
|
|
variant<_Types...>>;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-04-23 14:48:18 +02:00
|
|
|
template<typename _Tp>
|
|
|
|
static constexpr bool __not_self
|
|
|
|
= !is_same_v<__remove_cvref_t<_Tp>, variant>;
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename _Tp>
|
|
|
|
static constexpr bool
|
|
|
|
__exactly_once = __detail::__variant::__exactly_once<_Tp, _Types...>;
|
|
|
|
|
|
|
|
template<typename _Tp>
|
2019-05-16 22:30:35 +02:00
|
|
|
static constexpr size_t __accepted_index
|
|
|
|
= __detail::__variant::__accepted_index<_Tp, variant>::value;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-04-23 14:48:18 +02:00
|
|
|
template<size_t _Np, typename = enable_if_t<(_Np < sizeof...(_Types))>>
|
|
|
|
using __to_type = variant_alternative_t<_Np, variant>;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
2019-04-23 14:48:18 +02:00
|
|
|
template<typename _Tp, typename = enable_if_t<__not_self<_Tp>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
using __accepted_type = __to_type<__accepted_index<_Tp>>;
|
|
|
|
|
|
|
|
template<typename _Tp>
|
|
|
|
static constexpr size_t __index_of =
|
|
|
|
__detail::__variant::__index_of_v<_Tp, _Types...>;
|
|
|
|
|
2017-06-27 20:19:03 +02:00
|
|
|
using _Traits = __detail::__variant::_Traits<_Types...>;
|
|
|
|
|
2019-04-23 14:48:18 +02:00
|
|
|
template<typename _Tp>
|
|
|
|
struct __is_in_place_tag : false_type { };
|
|
|
|
template<typename _Tp>
|
|
|
|
struct __is_in_place_tag<in_place_type_t<_Tp>> : true_type { };
|
|
|
|
template<size_t _Np>
|
|
|
|
struct __is_in_place_tag<in_place_index_t<_Np>> : true_type { };
|
|
|
|
|
|
|
|
template<typename _Tp>
|
|
|
|
static constexpr bool __not_in_place_tag
|
|
|
|
= !__is_in_place_tag<__remove_cvref_t<_Tp>>::value;
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
public:
|
2017-06-27 20:19:03 +02:00
|
|
|
variant() = default;
|
|
|
|
variant(const variant& __rhs) = default;
|
|
|
|
variant(variant&&) = default;
|
|
|
|
variant& operator=(const variant&) = default;
|
|
|
|
variant& operator=(variant&&) = default;
|
|
|
|
~variant() = default;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _Tp,
|
2019-04-23 14:48:18 +02:00
|
|
|
typename = enable_if_t<sizeof...(_Types) != 0>,
|
|
|
|
typename = enable_if_t<__not_in_place_tag<_Tp>>,
|
|
|
|
typename _Tj = __accepted_type<_Tp&&>,
|
|
|
|
typename = enable_if_t<__exactly_once<_Tj>
|
|
|
|
&& is_constructible_v<_Tj, _Tp>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
constexpr
|
|
|
|
variant(_Tp&& __t)
|
2019-04-23 14:48:18 +02:00
|
|
|
noexcept(is_nothrow_constructible_v<_Tj, _Tp>)
|
2019-05-16 22:30:35 +02:00
|
|
|
: variant(in_place_index<__accepted_index<_Tp>>,
|
2017-07-23 10:41:35 +02:00
|
|
|
std::forward<_Tp>(__t))
|
2019-04-03 11:47:51 +02:00
|
|
|
{ }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _Tp, typename... _Args,
|
|
|
|
typename = enable_if_t<__exactly_once<_Tp>
|
2019-04-23 14:48:18 +02:00
|
|
|
&& is_constructible_v<_Tp, _Args...>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
constexpr explicit
|
|
|
|
variant(in_place_type_t<_Tp>, _Args&&... __args)
|
2017-06-27 20:19:03 +02:00
|
|
|
: variant(in_place_index<__index_of<_Tp>>,
|
2017-07-23 10:41:35 +02:00
|
|
|
std::forward<_Args>(__args)...)
|
2019-04-03 11:47:51 +02:00
|
|
|
{ }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _Tp, typename _Up, typename... _Args,
|
|
|
|
typename = enable_if_t<__exactly_once<_Tp>
|
2019-04-23 14:48:18 +02:00
|
|
|
&& is_constructible_v<_Tp,
|
|
|
|
initializer_list<_Up>&, _Args...>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
constexpr explicit
|
|
|
|
variant(in_place_type_t<_Tp>, initializer_list<_Up> __il,
|
|
|
|
_Args&&... __args)
|
Implement P0504R0 (Revisiting in-place tag types for any/optional/variant).
Implement P0504R0 (Revisiting in-place tag types for
any/optional/variant).
* include/std/any (any(_ValueType&& __value)): Constrain
the __is_in_place_type with the decayed type.
(make_any): Adjust to use the new tag type.
* include/std/utility (in_place_tag): Remove.
(in_place_t): Turn into a non-reference tag type.
(__in_place, __in_place_type, __in_place_index): Remove.
(in_place): Turn into an inline variable of non-reference
tag type.
(in_place<_Tp>): Remove.
(in_place_index<_Idx>): Remove.
(in_place_type_t): New.
(in_place_type): Turn into a variable template of non-reference
type.
(in_place_index_t): New.
(in_place_index): Turn into a variable template of non-reference
type.
* include/std/variant
(_Variant_storage(in_place_index_t<_Np>, _Args&&...)): Adjust to
use the new tag type.
(_Union(in_place_index_t<0>, _Args&&...)): Likewise.
(_Union(in_place_index_t<_Np>, _Args&&...)): Likewise.
(_Variant_base()): Likewise.
(variant(_Tp&&)): Likewise.
(variant(in_place_type_t<_Tp>, _Args&&...)): Likewise.
(variant(in_place_type_t<_Tp>, initializer_list<_Up>,
_Args&&...)): Likewise.
(variant(in_place_index_t<_Np>, _Args&&...)): Likewise.
(variant(in_place_index_t<_Np>, initializer_list<_Up>,
_Args&&...)): Likewise
(variant(allocator_arg_t, const _Alloc&)): Likewise.
(variant(allocator_arg_t, const _Alloc&, _Tp&&)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_type_t<_Tp>,
_Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_type_t<_Tp>,
initializer_list<_Up>, _Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_index_t<_Np>,
_Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_index_t<_Np>,
initializer_list<_Up>, _Args&&...)): Likewise.
(emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/cons/explicit.cc: Likewise.
* testsuite/20_util/any/cons/in_place.cc: Likewise.
* testsuite/20_util/any/requirements.cc: Add tests to
check that any is not constructible from the new in_place_type_t
of any value category.
* testsuite/20_util/in_place/requirements.cc: Adjust to
use the new tag type.
* testsuite/20_util/variant/compile.cc: Likewise.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r242401
2016-11-14 21:47:44 +01:00
|
|
|
: variant(in_place_index<__index_of<_Tp>>, __il,
|
2016-09-22 11:56:54 +02:00
|
|
|
std::forward<_Args>(__args)...)
|
2019-04-03 11:47:51 +02:00
|
|
|
{ }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<size_t _Np, typename... _Args,
|
2019-04-23 14:48:18 +02:00
|
|
|
typename _Tp = __to_type<_Np>,
|
|
|
|
typename = enable_if_t<is_constructible_v<_Tp, _Args...>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
constexpr explicit
|
|
|
|
variant(in_place_index_t<_Np>, _Args&&... __args)
|
Implement P0504R0 (Revisiting in-place tag types for any/optional/variant).
Implement P0504R0 (Revisiting in-place tag types for
any/optional/variant).
* include/std/any (any(_ValueType&& __value)): Constrain
the __is_in_place_type with the decayed type.
(make_any): Adjust to use the new tag type.
* include/std/utility (in_place_tag): Remove.
(in_place_t): Turn into a non-reference tag type.
(__in_place, __in_place_type, __in_place_index): Remove.
(in_place): Turn into an inline variable of non-reference
tag type.
(in_place<_Tp>): Remove.
(in_place_index<_Idx>): Remove.
(in_place_type_t): New.
(in_place_type): Turn into a variable template of non-reference
type.
(in_place_index_t): New.
(in_place_index): Turn into a variable template of non-reference
type.
* include/std/variant
(_Variant_storage(in_place_index_t<_Np>, _Args&&...)): Adjust to
use the new tag type.
(_Union(in_place_index_t<0>, _Args&&...)): Likewise.
(_Union(in_place_index_t<_Np>, _Args&&...)): Likewise.
(_Variant_base()): Likewise.
(variant(_Tp&&)): Likewise.
(variant(in_place_type_t<_Tp>, _Args&&...)): Likewise.
(variant(in_place_type_t<_Tp>, initializer_list<_Up>,
_Args&&...)): Likewise.
(variant(in_place_index_t<_Np>, _Args&&...)): Likewise.
(variant(in_place_index_t<_Np>, initializer_list<_Up>,
_Args&&...)): Likewise
(variant(allocator_arg_t, const _Alloc&)): Likewise.
(variant(allocator_arg_t, const _Alloc&, _Tp&&)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_type_t<_Tp>,
_Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_type_t<_Tp>,
initializer_list<_Up>, _Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_index_t<_Np>,
_Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_index_t<_Np>,
initializer_list<_Up>, _Args&&...)): Likewise.
(emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/cons/explicit.cc: Likewise.
* testsuite/20_util/any/cons/in_place.cc: Likewise.
* testsuite/20_util/any/requirements.cc: Add tests to
check that any is not constructible from the new in_place_type_t
of any value category.
* testsuite/20_util/in_place/requirements.cc: Adjust to
use the new tag type.
* testsuite/20_util/variant/compile.cc: Likewise.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r242401
2016-11-14 21:47:44 +01:00
|
|
|
: _Base(in_place_index<_Np>, std::forward<_Args>(__args)...),
|
2016-08-18 22:31:26 +02:00
|
|
|
_Default_ctor_enabler(_Enable_default_constructor_tag{})
|
2019-04-03 11:47:51 +02:00
|
|
|
{ }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<size_t _Np, typename _Up, typename... _Args,
|
2019-04-23 14:48:18 +02:00
|
|
|
typename _Tp = __to_type<_Np>,
|
|
|
|
typename = enable_if_t<is_constructible_v<_Tp,
|
|
|
|
initializer_list<_Up>&,
|
|
|
|
_Args...>>>
|
2016-08-18 22:31:26 +02:00
|
|
|
constexpr explicit
|
|
|
|
variant(in_place_index_t<_Np>, initializer_list<_Up> __il,
|
|
|
|
_Args&&... __args)
|
Implement P0504R0 (Revisiting in-place tag types for any/optional/variant).
Implement P0504R0 (Revisiting in-place tag types for
any/optional/variant).
* include/std/any (any(_ValueType&& __value)): Constrain
the __is_in_place_type with the decayed type.
(make_any): Adjust to use the new tag type.
* include/std/utility (in_place_tag): Remove.
(in_place_t): Turn into a non-reference tag type.
(__in_place, __in_place_type, __in_place_index): Remove.
(in_place): Turn into an inline variable of non-reference
tag type.
(in_place<_Tp>): Remove.
(in_place_index<_Idx>): Remove.
(in_place_type_t): New.
(in_place_type): Turn into a variable template of non-reference
type.
(in_place_index_t): New.
(in_place_index): Turn into a variable template of non-reference
type.
* include/std/variant
(_Variant_storage(in_place_index_t<_Np>, _Args&&...)): Adjust to
use the new tag type.
(_Union(in_place_index_t<0>, _Args&&...)): Likewise.
(_Union(in_place_index_t<_Np>, _Args&&...)): Likewise.
(_Variant_base()): Likewise.
(variant(_Tp&&)): Likewise.
(variant(in_place_type_t<_Tp>, _Args&&...)): Likewise.
(variant(in_place_type_t<_Tp>, initializer_list<_Up>,
_Args&&...)): Likewise.
(variant(in_place_index_t<_Np>, _Args&&...)): Likewise.
(variant(in_place_index_t<_Np>, initializer_list<_Up>,
_Args&&...)): Likewise
(variant(allocator_arg_t, const _Alloc&)): Likewise.
(variant(allocator_arg_t, const _Alloc&, _Tp&&)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_type_t<_Tp>,
_Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_type_t<_Tp>,
initializer_list<_Up>, _Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_index_t<_Np>,
_Args&&...)): Likewise.
(variant(allocator_arg_t, const _Alloc&, in_place_index_t<_Np>,
initializer_list<_Up>, _Args&&...)): Likewise.
(emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/cons/explicit.cc: Likewise.
* testsuite/20_util/any/cons/in_place.cc: Likewise.
* testsuite/20_util/any/requirements.cc: Add tests to
check that any is not constructible from the new in_place_type_t
of any value category.
* testsuite/20_util/in_place/requirements.cc: Adjust to
use the new tag type.
* testsuite/20_util/variant/compile.cc: Likewise.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r242401
2016-11-14 21:47:44 +01:00
|
|
|
: _Base(in_place_index<_Np>, __il, std::forward<_Args>(__args)...),
|
2016-08-18 22:31:26 +02:00
|
|
|
_Default_ctor_enabler(_Enable_default_constructor_tag{})
|
2019-04-03 11:47:51 +02:00
|
|
|
{ }
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
template<typename _Tp>
|
|
|
|
enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
|
2019-04-23 14:48:18 +02:00
|
|
|
&& is_constructible_v<__accepted_type<_Tp&&>, _Tp>
|
|
|
|
&& is_assignable_v<__accepted_type<_Tp&&>&, _Tp>,
|
|
|
|
variant&>
|
2016-08-18 22:31:26 +02:00
|
|
|
operator=(_Tp&& __rhs)
|
2019-04-23 14:48:18 +02:00
|
|
|
noexcept(is_nothrow_assignable_v<__accepted_type<_Tp&&>&, _Tp>
|
|
|
|
&& is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp>)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-05-16 22:30:35 +02:00
|
|
|
constexpr auto __index = __accepted_index<_Tp>;
|
2016-08-18 22:31:26 +02:00
|
|
|
if (index() == __index)
|
2016-09-22 10:45:55 +02:00
|
|
|
std::get<__index>(*this) = std::forward<_Tp>(__rhs);
|
2016-08-18 22:31:26 +02:00
|
|
|
else
|
Implement LWG 2904 for std::variant assignment
* include/std/variant (__variant_construct): Use template parameter
type instead of equivalent decltype-specifier.
(_Move_ctor_base<false, Types...>::_Move_ctor_base(_Move_ctor_base&&)):
Replace forward with move.
(_Move_ctor_base<false, Types...>::_M_destructive_move)
(_Move_ctor_base<false, Types...>::_M_destructive_copy)
(_Move_ctor_base<true, Types...>::_M_destructive_move)
(_Move_ctor_base<true, Types...>::_M_destructive_copy): Only set the
index after construction succeeds.
(_Copy_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use __remove_cvref_t instead
of remove_reference so that is_nothrow_move_constructible check
doesn't use a const rvalue parameter. In the potentially-throwing case
construct a temporary and move assign it, as per LWG 2904.
(_Move_assign_base<false, Types...>::operator=): Remove redundant
if-constexpr checks that are always true. Use emplace as per LWG 2904.
(variant::operator=(T&&)): Only use emplace conditionally, otherwise
construct a temporary and move assign from it, as per LWG 2904.
* testsuite/20_util/variant/exception_safety.cc: Check that
assignment operators have strong exception safety guarantee.
From-SVN: r270525
2019-04-24 01:01:12 +02:00
|
|
|
{
|
|
|
|
using _Tj = __accepted_type<_Tp&&>;
|
|
|
|
if constexpr (is_nothrow_constructible_v<_Tj, _Tp>
|
|
|
|
|| !is_nothrow_move_constructible_v<_Tj>)
|
|
|
|
this->emplace<__index>(std::forward<_Tp>(__rhs));
|
|
|
|
else
|
|
|
|
operator=(variant(std::forward<_Tp>(__rhs)));
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename... _Args>
|
Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value.
Implement LWG 2857, {variant,optional,any}::emplace should
return the constructed value.
* include/std/any (emplace(_Args&&...)): Change the return type and
return a reference to the constructed value.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/optional (emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/variant (emplace<_Tp>(_Args&&...)): Likewise.
(emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise.
(emplace<_Np>(_Args&&...)): Likewise.
(emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/assign/emplace.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/any/misc/any_cast_neg.cc: Adjust.
* testsuite/20_util/optional/assignment/6.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r246182
2017-03-16 00:13:20 +01:00
|
|
|
enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>,
|
|
|
|
_Tp&>
|
2016-12-06 12:26:48 +01:00
|
|
|
emplace(_Args&&... __args)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-03 11:47:51 +02:00
|
|
|
constexpr size_t __index = __index_of<_Tp>;
|
|
|
|
return this->emplace<__index>(std::forward<_Args>(__args)...);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Tp, typename _Up, typename... _Args>
|
2016-12-06 12:26:48 +01:00
|
|
|
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
|
Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value.
Implement LWG 2857, {variant,optional,any}::emplace should
return the constructed value.
* include/std/any (emplace(_Args&&...)): Change the return type and
return a reference to the constructed value.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/optional (emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/variant (emplace<_Tp>(_Args&&...)): Likewise.
(emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise.
(emplace<_Np>(_Args&&...)): Likewise.
(emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/assign/emplace.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/any/misc/any_cast_neg.cc: Adjust.
* testsuite/20_util/optional/assignment/6.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r246182
2017-03-16 00:13:20 +01:00
|
|
|
&& __exactly_once<_Tp>,
|
|
|
|
_Tp&>
|
2016-12-06 12:26:48 +01:00
|
|
|
emplace(initializer_list<_Up> __il, _Args&&... __args)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-03 11:47:51 +02:00
|
|
|
constexpr size_t __index = __index_of<_Tp>;
|
|
|
|
return this->emplace<__index>(__il, std::forward<_Args>(__args)...);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Args>
|
2016-12-06 12:26:48 +01:00
|
|
|
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
|
Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value.
Implement LWG 2857, {variant,optional,any}::emplace should
return the constructed value.
* include/std/any (emplace(_Args&&...)): Change the return type and
return a reference to the constructed value.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/optional (emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/variant (emplace<_Tp>(_Args&&...)): Likewise.
(emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise.
(emplace<_Np>(_Args&&...)): Likewise.
(emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/assign/emplace.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/any/misc/any_cast_neg.cc: Adjust.
* testsuite/20_util/optional/assignment/6.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r246182
2017-03-16 00:13:20 +01:00
|
|
|
_Args...>,
|
|
|
|
variant_alternative_t<_Np, variant>&>
|
2016-12-06 12:26:48 +01:00
|
|
|
emplace(_Args&&... __args)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
using type = variant_alternative_t<_Np, variant>;
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// Provide the strong exception-safety guarantee when possible,
|
|
|
|
// to avoid becoming valueless.
|
|
|
|
if constexpr (is_nothrow_constructible_v<type, _Args...>)
|
|
|
|
{
|
|
|
|
this->_M_reset();
|
|
|
|
__variant_construct_by_index<_Np>(*this,
|
|
|
|
std::forward<_Args>(__args)...);
|
|
|
|
}
|
|
|
|
else if constexpr (is_scalar_v<type>)
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
{
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// This might invoke a potentially-throwing conversion operator:
|
|
|
|
const type __tmp(std::forward<_Args>(__args)...);
|
|
|
|
// But these steps won't throw:
|
|
|
|
this->_M_reset();
|
|
|
|
__variant_construct_by_index<_Np>(*this, __tmp);
|
|
|
|
}
|
Fix std::variant regression caused by never-valueless optimization
A regression was introduced by the recent changes to provide the strong
exception safety guarantee for "never valueless" types that have O(1),
non-throwing move assignment. The problematic code is:
else if constexpr (__detail::__variant::_Never_valueless_alt<type>())
{
// This construction might throw:
variant __tmp(in_place_index<_Np>, __il,
std::forward<_Args>(__args)...);
// But _Never_valueless_alt<type> means this won't:
*this = std::move(__tmp);
}
When the variant is not assignable, the assignment is ill-formed, so
should not be attempted. When the variant has a copy assignment operator
but not a move assignment operator, the assignment performs a copy
assignment and that could throw, so should not be attempted.
The solution is to only take that branch when the variant has a move
assignment operator, which is determined by the _Traits::_S_move_assign
constant. When that is false the strong exception safety guarantee is
not possible, and so the __never_valueless function should also depend
on _S_move_assign.
While testing the fixes for this I noticed that the partial
specialization _Never_valueless_alt<basic_string<C,T,A>> incorrectly
assumed that is_nothrow_move_constructible<basic_string<C,T,A>> is
always true, but that's wrong for fully-dynamic COW strings. Fix the
partial specialization, and improve the comment describing
_Never_valueless_alt to be clear it depends on move construction as well
as move assignment.
Finally, I also observed that _Variant_storage<false, T...>::_M_valid()
was not taking advantage of the __never_valueless<T...>() function to
avoid a runtime check. Only the _Variant_storage<true, T...>::_M_valid()
function was using __never_valueless. That is also fixed.
PR libstdc++/87431
* include/bits/basic_string.h (_Never_valueless_alt): Make partial
specialization also depend on is_nothrow_move_constructible.
* include/std/variant (__detail::__variant::__never_valueless()):
Only true if the variant would have a move assignment operator.
(__detail::__variant::_Variant_storage<false, T...>::_M_valid()):
Check __never_valueless<T...>().
(variant::emplace): Only perform non-throwing move assignments
for never-valueless alternatives if the variant has a move assignment
operator.
* testsuite/20_util/variant/compile.cc: Check that never-valueless
types can be emplaced into non-assignable variants.
* testsuite/20_util/variant/run.cc: Check that never-valueless types
don't get copied when emplaced into non-assignable variants.
From-SVN: r270502
2019-04-23 11:55:33 +02:00
|
|
|
else if constexpr (__detail::__variant::_Never_valueless_alt<type>()
|
|
|
|
&& _Traits::_S_move_assign)
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
{
|
|
|
|
// This construction might throw:
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
variant __tmp(in_place_index<_Np>,
|
|
|
|
std::forward<_Args>(__args)...);
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// But _Never_valueless_alt<type> means this won't:
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
*this = std::move(__tmp);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
else
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// This case only provides the basic exception-safety guarantee,
|
|
|
|
// i.e. the variant can become valueless.
|
|
|
|
this->_M_reset();
|
|
|
|
__try
|
|
|
|
{
|
|
|
|
__variant_construct_by_index<_Np>(*this,
|
|
|
|
std::forward<_Args>(__args)...);
|
|
|
|
}
|
|
|
|
__catch (...)
|
|
|
|
{
|
|
|
|
this->_M_index = variant_npos;
|
|
|
|
__throw_exception_again;
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value.
Implement LWG 2857, {variant,optional,any}::emplace should
return the constructed value.
* include/std/any (emplace(_Args&&...)): Change the return type and
return a reference to the constructed value.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/optional (emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/variant (emplace<_Tp>(_Args&&...)): Likewise.
(emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise.
(emplace<_Np>(_Args&&...)): Likewise.
(emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/assign/emplace.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/any/misc/any_cast_neg.cc: Adjust.
* testsuite/20_util/optional/assignment/6.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r246182
2017-03-16 00:13:20 +01:00
|
|
|
return std::get<_Np>(*this);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename _Up, typename... _Args>
|
2016-12-06 12:26:48 +01:00
|
|
|
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
|
Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value.
Implement LWG 2857, {variant,optional,any}::emplace should
return the constructed value.
* include/std/any (emplace(_Args&&...)): Change the return type and
return a reference to the constructed value.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/optional (emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/variant (emplace<_Tp>(_Args&&...)): Likewise.
(emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise.
(emplace<_Np>(_Args&&...)): Likewise.
(emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/assign/emplace.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/any/misc/any_cast_neg.cc: Adjust.
* testsuite/20_util/optional/assignment/6.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r246182
2017-03-16 00:13:20 +01:00
|
|
|
initializer_list<_Up>&, _Args...>,
|
|
|
|
variant_alternative_t<_Np, variant>&>
|
2016-12-06 12:26:48 +01:00
|
|
|
emplace(initializer_list<_Up> __il, _Args&&... __args)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
using type = variant_alternative_t<_Np, variant>;
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// Provide the strong exception-safety guarantee when possible,
|
|
|
|
// to avoid becoming valueless.
|
|
|
|
if constexpr (is_nothrow_constructible_v<type,
|
|
|
|
initializer_list<_Up>&,
|
|
|
|
_Args...>)
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
{
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
this->_M_reset();
|
|
|
|
__variant_construct_by_index<_Np>(*this, __il,
|
|
|
|
std::forward<_Args>(__args)...);
|
|
|
|
}
|
Fix std::variant regression caused by never-valueless optimization
A regression was introduced by the recent changes to provide the strong
exception safety guarantee for "never valueless" types that have O(1),
non-throwing move assignment. The problematic code is:
else if constexpr (__detail::__variant::_Never_valueless_alt<type>())
{
// This construction might throw:
variant __tmp(in_place_index<_Np>, __il,
std::forward<_Args>(__args)...);
// But _Never_valueless_alt<type> means this won't:
*this = std::move(__tmp);
}
When the variant is not assignable, the assignment is ill-formed, so
should not be attempted. When the variant has a copy assignment operator
but not a move assignment operator, the assignment performs a copy
assignment and that could throw, so should not be attempted.
The solution is to only take that branch when the variant has a move
assignment operator, which is determined by the _Traits::_S_move_assign
constant. When that is false the strong exception safety guarantee is
not possible, and so the __never_valueless function should also depend
on _S_move_assign.
While testing the fixes for this I noticed that the partial
specialization _Never_valueless_alt<basic_string<C,T,A>> incorrectly
assumed that is_nothrow_move_constructible<basic_string<C,T,A>> is
always true, but that's wrong for fully-dynamic COW strings. Fix the
partial specialization, and improve the comment describing
_Never_valueless_alt to be clear it depends on move construction as well
as move assignment.
Finally, I also observed that _Variant_storage<false, T...>::_M_valid()
was not taking advantage of the __never_valueless<T...>() function to
avoid a runtime check. Only the _Variant_storage<true, T...>::_M_valid()
function was using __never_valueless. That is also fixed.
PR libstdc++/87431
* include/bits/basic_string.h (_Never_valueless_alt): Make partial
specialization also depend on is_nothrow_move_constructible.
* include/std/variant (__detail::__variant::__never_valueless()):
Only true if the variant would have a move assignment operator.
(__detail::__variant::_Variant_storage<false, T...>::_M_valid()):
Check __never_valueless<T...>().
(variant::emplace): Only perform non-throwing move assignments
for never-valueless alternatives if the variant has a move assignment
operator.
* testsuite/20_util/variant/compile.cc: Check that never-valueless
types can be emplaced into non-assignable variants.
* testsuite/20_util/variant/run.cc: Check that never-valueless types
don't get copied when emplaced into non-assignable variants.
From-SVN: r270502
2019-04-23 11:55:33 +02:00
|
|
|
else if constexpr (__detail::__variant::_Never_valueless_alt<type>()
|
|
|
|
&& _Traits::_S_move_assign)
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
{
|
|
|
|
// This construction might throw:
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
variant __tmp(in_place_index<_Np>, __il,
|
|
|
|
std::forward<_Args>(__args)...);
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// But _Never_valueless_alt<type> means this won't:
|
PR libstdc++/87431 fix regression introduced by r264574
The previous patch for PR 87431 assumed that initialing a scalar type
could not throw, but it can obtain its value via a conversion operator,
which could throw. This meant the variant could get into a valueless
state, but the valueless_by_exception() member function would always
return false.
This patch fixes it by changing the emplace members to have strong
exception safety when initializing a contained value of trivially
copyable type. The _M_valid() member gets a corresponding change to
always return true for trivially copyable types, not just scalar types.
Strong exception safety (i.e. never becoming valueless) is achieved by
only replacing the current contained value once any potentially throwing
operations have completed. If constructing the new contained value can
throw then a new std::variant object is constructed to hold it, and then
move-assigned to *this (which won't throw).
PR libstdc++/87431
* include/std/variant (_Variant_storage<true, _Types...>::_M_valid):
Check is_trivially_copyable instead of is_scalar.
(variant::emplace<N, Args>(Args&&...)): If construction of the new
contained value can throw and its type is trivially copyable then
construct into a temporary variant and move from it, to provide the
strong exception safety guarantee.
(variant::emplace<N, U, Args>(initializer_list<U>, Args&&...)):
Likewise.
* testsuite/20_util/variant/87431.cc: New test.
* testsuite/20_util/variant/run.cc: Adjust test so that throwing
conversion causes valueless state.
From-SVN: r267614
2019-01-06 21:52:34 +01:00
|
|
|
*this = std::move(__tmp);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
else
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
PR libstdc++/87431 re-adjust never-valueless optimizations
Avoid creating arbitrarily large objects on the stack when emplacing
trivially copyable objects into a variant. Currently we provide the
strong exception-safety guarantee for all trivially copyable types, by
constructing a second variant and then doing a non-throwing move
assignment from the temporary. This patch restricts that behaviour to
trivially copyable types that are no larger than 256 bytes. For larger
types the object will be emplaced directly into the variant, and if its
initialization throws then the variant becomes valueless.
Also implement Antony Polukhin's suggestion to whitelist specific types
that are not trivially copyable but can be efficiently move-assigned.
Emplacing those types will never cause a variant to become valueless.
The whitelisted types are: std::shared_ptr, std::weak_ptr,
std::unique_ptr, std::function, and std::any. Additionally,
std::basic_string, std::vector, and __gnu_debug::vector are whitelisted
if their allocator traits give them a non-throwing move assignment
operator. Specifically, this means std::string is whitelisted, but
std::pmr::string is not.
As part of this patch, additional if-constexpr branches are added for
the cases where the initialization is known to be non-throwing (so the
overhead of the try-catch block can be avoided) and where a scalar is
being produced by a potentially-throwing conversion operator (so that
the overhead of constructing and move-assigning a variant is avoided).
These changes should have no semantic effect, just better codegen.
PR libstdc++/87431 (again)
* include/bits/basic_string.h (__variant::_Never_valueless_alt):
Define partial specialization for basic_string.
* include/bits/shared_ptr.h (_Never_valueless_alt): Likewise for
shared_ptr and weak_ptr.
* include/bits/std_function.h (_Never_valueless_alt): Likewise for
function.
* include/bits/stl_vector.h (_Never_valueless_alt): Likewise for
vector.
* include/bits/unique_ptr.h (_Never_valueless_alt): Likewise for
unique_ptr.
* include/debug/vector (_Never_valueless_alt): Likewise for debug
vector.
* include/std/any (_Never_valueless_alt): Define explicit
specialization for any.
* include/std/variant (_Never_valueless_alt): Define primary template.
(__never_valueless): Use _Never_valueless_alt instead of
is_trivially_copyable.
(variant::emplace<N>(Args&&...)): Add special case for non-throwing
initializations to avoid try-catch overhead. Add special case for
scalars produced by potentially-throwing conversions. Use
_Never_valueless_alt instead of is_trivially_copyable for the
remaining strong exception-safety cases.
(variant::emplace<N>(initializer_list<U>, Args&&...)): Likewise.
* testsuite/20_util/variant/87431.cc: Run both test functions.
* testsuite/20_util/variant/exception_safety.cc: New test.
* testsuite/20_util/variant/run.cc: Use pmr::string instead of string,
so the variant becomes valueless.
From-SVN: r270170
2019-04-05 18:56:09 +02:00
|
|
|
// This case only provides the basic exception-safety guarantee,
|
|
|
|
// i.e. the variant can become valueless.
|
|
|
|
this->_M_reset();
|
|
|
|
__try
|
|
|
|
{
|
|
|
|
__variant_construct_by_index<_Np>(*this, __il,
|
|
|
|
std::forward<_Args>(__args)...);
|
|
|
|
}
|
|
|
|
__catch (...)
|
|
|
|
{
|
|
|
|
this->_M_index = variant_npos;
|
|
|
|
__throw_exception_again;
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
Implement LWG 2857, {variant,optional,any}::emplace should return the constructed value.
Implement LWG 2857, {variant,optional,any}::emplace should
return the constructed value.
* include/std/any (emplace(_Args&&...)): Change the return type and
return a reference to the constructed value.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/optional (emplace(_Args&&...)): Likewise.
(emplace(initializer_list<_Up>, _Args&&...)): Likewise.
* include/std/variant (emplace<_Tp>(_Args&&...)): Likewise.
(emplace<_Tp>(initializer_list<_Up>, _Args&&...)): Likewise.
(emplace<_Np>(_Args&&...)): Likewise.
(emplace<_Np>(initializer_list<_Up>, _Args&&...)): Likewise.
* testsuite/20_util/any/assign/emplace.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/any/misc/any_cast_neg.cc: Adjust.
* testsuite/20_util/optional/assignment/6.cc: Add tests for
checking the return value of emplace.
* testsuite/20_util/variant/run.cc: Likewise.
From-SVN: r246182
2017-03-16 00:13:20 +01:00
|
|
|
return std::get<_Np>(*this);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool valueless_by_exception() const noexcept
|
|
|
|
{ return !this->_M_valid(); }
|
|
|
|
|
|
|
|
constexpr size_t index() const noexcept
|
2019-09-23 17:54:16 +02:00
|
|
|
{
|
|
|
|
using __index_type = typename _Base::__index_type;
|
2019-09-24 16:17:08 +02:00
|
|
|
if constexpr (__detail::__variant::__never_valueless<_Types...>())
|
2019-09-23 17:54:16 +02:00
|
|
|
return this->_M_index;
|
|
|
|
else if constexpr (sizeof...(_Types) <= __index_type(-1) / 2)
|
|
|
|
return make_signed_t<__index_type>(this->_M_index);
|
|
|
|
else
|
|
|
|
return size_t(__index_type(this->_M_index + 1)) - 1;
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
swap(variant& __rhs)
|
2017-01-06 16:27:01 +01:00
|
|
|
noexcept((__is_nothrow_swappable<_Types>::value && ...)
|
2016-12-06 12:26:48 +01:00
|
|
|
&& is_nothrow_move_constructible_v<variant>)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__detail::__variant::__raw_idx_visit(
|
|
|
|
[this, &__rhs](auto&& __rhs_mem, auto __rhs_index) mutable
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
if constexpr (__rhs_index != variant_npos)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
if (this->index() == __rhs_index)
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
auto& __this_mem =
|
|
|
|
std::get<__rhs_index>(*this);
|
2019-03-06 13:56:05 +01:00
|
|
|
using std::swap;
|
|
|
|
swap(__this_mem, __rhs_mem);
|
|
|
|
}
|
2019-04-01 15:57:41 +02:00
|
|
|
else
|
|
|
|
{
|
2019-05-16 22:30:27 +02:00
|
|
|
if (!this->valueless_by_exception()) [[__likely__]]
|
2019-04-01 15:57:41 +02:00
|
|
|
{
|
|
|
|
auto __tmp(std::move(__rhs_mem));
|
|
|
|
__rhs = std::move(*this);
|
|
|
|
this->_M_destructive_move(__rhs_index,
|
|
|
|
std::move(__tmp));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->_M_destructive_move(__rhs_index,
|
|
|
|
std::move(__rhs_mem));
|
|
|
|
__rhs._M_reset();
|
|
|
|
}
|
|
|
|
}
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
2019-03-06 13:56:05 +01:00
|
|
|
else
|
|
|
|
{
|
2019-05-16 22:30:27 +02:00
|
|
|
if (!this->valueless_by_exception()) [[__likely__]]
|
2019-03-06 13:56:05 +01:00
|
|
|
{
|
2019-04-01 15:57:41 +02:00
|
|
|
__rhs = std::move(*this);
|
2019-03-06 13:56:05 +01:00
|
|
|
this->_M_reset();
|
|
|
|
}
|
|
|
|
}
|
2019-04-01 15:57:41 +02:00
|
|
|
}, __rhs);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
private:
|
|
|
|
|
2018-09-13 15:47:14 +02:00
|
|
|
#if defined(__clang__) && __clang_major__ <= 7
|
2018-03-26 15:09:10 +02:00
|
|
|
public:
|
|
|
|
using _Base::_M_u; // See https://bugs.llvm.org/show_bug.cgi?id=31852
|
|
|
|
private:
|
|
|
|
#endif
|
|
|
|
|
2016-12-06 12:20:13 +01:00
|
|
|
template<size_t _Np, typename _Vp>
|
2019-05-10 23:41:19 +02:00
|
|
|
friend constexpr decltype(auto)
|
|
|
|
__detail::__variant::__get(_Vp&& __v) noexcept;
|
2016-12-06 12:20:13 +01:00
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<typename _Vp>
|
2019-05-10 23:41:19 +02:00
|
|
|
friend void*
|
|
|
|
__detail::__variant::__get_storage(_Vp&& __v) noexcept;
|
2016-12-06 12:20:13 +01:00
|
|
|
|
2017-02-15 10:01:06 +01:00
|
|
|
#define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP) \
|
|
|
|
template<typename... _Tp> \
|
|
|
|
friend constexpr bool \
|
|
|
|
operator __OP(const variant<_Tp...>& __lhs, \
|
|
|
|
const variant<_Tp...>& __rhs);
|
|
|
|
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(<)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(<=)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(==)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(!=)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(>=)
|
|
|
|
_VARIANT_RELATION_FUNCTION_TEMPLATE(>)
|
2016-12-06 12:20:13 +01:00
|
|
|
|
2017-02-15 10:01:06 +01:00
|
|
|
#undef _VARIANT_RELATION_FUNCTION_TEMPLATE
|
2016-08-18 22:31:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
2016-12-06 12:20:13 +01:00
|
|
|
constexpr variant_alternative_t<_Np, variant<_Types...>>&
|
2016-08-18 22:31:26 +02:00
|
|
|
get(variant<_Types...>& __v)
|
|
|
|
{
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
2016-08-18 22:31:26 +02:00
|
|
|
if (__v.index() != _Np)
|
2019-05-17 16:36:37 +02:00
|
|
|
__throw_bad_variant_access(__v.valueless_by_exception());
|
2016-12-06 12:20:13 +01:00
|
|
|
return __detail::__variant::__get<_Np>(__v);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
2016-12-06 12:20:13 +01:00
|
|
|
constexpr variant_alternative_t<_Np, variant<_Types...>>&&
|
2016-08-18 22:31:26 +02:00
|
|
|
get(variant<_Types...>&& __v)
|
|
|
|
{
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
2016-08-18 22:31:26 +02:00
|
|
|
if (__v.index() != _Np)
|
2019-05-17 16:36:37 +02:00
|
|
|
__throw_bad_variant_access(__v.valueless_by_exception());
|
2016-12-06 12:20:13 +01:00
|
|
|
return __detail::__variant::__get<_Np>(std::move(__v));
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
2016-12-06 12:20:13 +01:00
|
|
|
constexpr const variant_alternative_t<_Np, variant<_Types...>>&
|
2016-08-18 22:31:26 +02:00
|
|
|
get(const variant<_Types...>& __v)
|
|
|
|
{
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
2016-08-18 22:31:26 +02:00
|
|
|
if (__v.index() != _Np)
|
2019-05-17 16:36:37 +02:00
|
|
|
__throw_bad_variant_access(__v.valueless_by_exception());
|
2016-12-06 12:20:13 +01:00
|
|
|
return __detail::__variant::__get<_Np>(__v);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t _Np, typename... _Types>
|
2016-12-06 12:20:13 +01:00
|
|
|
constexpr const variant_alternative_t<_Np, variant<_Types...>>&&
|
2016-08-18 22:31:26 +02:00
|
|
|
get(const variant<_Types...>&& __v)
|
|
|
|
{
|
|
|
|
static_assert(_Np < sizeof...(_Types),
|
2019-06-12 16:52:09 +02:00
|
|
|
"The index must be in [0, number of alternatives)");
|
2016-08-18 22:31:26 +02:00
|
|
|
if (__v.index() != _Np)
|
2019-05-17 16:36:37 +02:00
|
|
|
__throw_bad_variant_access(__v.valueless_by_exception());
|
2016-12-06 12:20:13 +01:00
|
|
|
return __detail::__variant::__get<_Np>(std::move(__v));
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
template<typename _Result_type, typename _Visitor, typename... _Variants>
|
2016-12-06 12:28:09 +01:00
|
|
|
constexpr decltype(auto)
|
2019-03-06 13:56:05 +01:00
|
|
|
__do_visit(_Visitor&& __visitor, _Variants&&... __variants)
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2016-12-06 12:28:09 +01:00
|
|
|
constexpr auto& __vtable = __detail::__variant::__gen_vtable<
|
|
|
|
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
|
|
|
|
|
|
|
|
auto __func_ptr = __vtable._M_access(__variants.index()...);
|
2016-09-22 11:56:54 +02:00
|
|
|
return (*__func_ptr)(std::forward<_Visitor>(__visitor),
|
2016-12-06 12:28:09 +01:00
|
|
|
std::forward<_Variants>(__variants)...);
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
|
2019-03-06 13:56:05 +01:00
|
|
|
template<typename _Visitor, typename... _Variants>
|
|
|
|
constexpr decltype(auto)
|
|
|
|
visit(_Visitor&& __visitor, _Variants&&... __variants)
|
|
|
|
{
|
|
|
|
if ((__variants.valueless_by_exception() || ...))
|
2019-05-17 16:36:37 +02:00
|
|
|
__throw_bad_variant_access("std::visit: variant is valueless");
|
2019-03-06 13:56:05 +01:00
|
|
|
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
using _Result_type = std::invoke_result_t<_Visitor,
|
|
|
|
decltype(std::get<0>(std::declval<_Variants>()))...>;
|
|
|
|
|
|
|
|
using _Tag = __detail::__variant::__deduce_visit_result<_Result_type>;
|
|
|
|
|
2019-05-15 23:19:39 +02:00
|
|
|
return std::__do_visit<_Tag>(std::forward<_Visitor>(__visitor),
|
|
|
|
std::forward<_Variants>(__variants)...);
|
2019-03-06 13:56:05 +01:00
|
|
|
}
|
|
|
|
|
2019-04-05 20:06:02 +02:00
|
|
|
#if __cplusplus > 201703L
|
|
|
|
template<typename _Res, typename _Visitor, typename... _Variants>
|
|
|
|
constexpr _Res
|
|
|
|
visit(_Visitor&& __visitor, _Variants&&... __variants)
|
|
|
|
{
|
|
|
|
if ((__variants.valueless_by_exception() || ...))
|
2019-05-17 16:36:37 +02:00
|
|
|
__throw_bad_variant_access("std::visit<R>: variant is valueless");
|
2019-04-05 20:06:02 +02:00
|
|
|
|
2019-05-15 23:19:39 +02:00
|
|
|
return std::__do_visit<_Res>(std::forward<_Visitor>(__visitor),
|
|
|
|
std::forward<_Variants>(__variants)...);
|
2019-04-05 20:06:02 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-01-21 16:38:23 +01:00
|
|
|
template<bool, typename... _Types>
|
|
|
|
struct __variant_hash_call_base_impl
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
size_t
|
|
|
|
operator()(const variant<_Types...>& __t) const
|
P0604R0 add invoke_result, is_invocable etc. for C++17
* include/bits/invoke.h (__invoke): Use __invoke_result instead of
result_of, and __is_nothrow_invocable instead of
__is_nothrow_callable.
* include/bits/shared_ptr_base.h (__shared_ptr): Use __is_invocable
instead of __is_callable.
* include/std/functional (invoke): use invoke_result_t instead of
result_of_t and is_nothrow_invocable instead of is_nothrow_callable.
(_Not_fn): Use __invoke_result instead of result_of.
* include/std/type_traits (__result_of_memobj, __result_of_memfun):
Remove partial specializations for reference_wrapper types.
(__result_of_impl): Use __inv_unwrap to strip reference_wrapper.
(__invoke_result): Define replacement for result_of and then use it to
define result_of.
(__is_callable_impl, __is_callable, __is_nothrow_callable): Replace
with __is_invocable_impl, __is_invocable, and __is_nothrow_invocable
respectively.
(invoke_result, invoke_result_t): Define for C++17.
(is_callable, is_nothrow_callable): Replace with is_invocable,
is_invocable_r, is_nothrow_invocable, and is_nothrow_invocable_r.
(is_callable_v, is_nothrow_callable_v): Replace with is_invocable_v,
is_invocable_r_v, is_nothrow_invocable_v, and is_nothrow_invocable_r_v.
* include/std/variant (hash<variant<T...>>): Use is_nothrow_invocable_v
instead of is_nothrow_callable_v.
* testsuite/20_util/function_objects/invoke/59768.cc: Remove unused
main function.
* testsuite/20_util/function_objects/not_fn/1.cc: Use is_invocable
instead of is_callable.
* testsuite/20_util/is_callable/*: Rename directory and adjust tests
to use new traits.
* testsuite/20_util/is_notjrow_callable/*: Likewise.
* testsuite/20_util/optional/hash.cc: Use is_invocable_v instead of
is_callable.
* testsuite/20_util/variant/hash.cc: Likewise.
From-SVN: r246036
2017-03-10 16:29:38 +01:00
|
|
|
noexcept((is_nothrow_invocable_v<hash<decay_t<_Types>>, _Types> && ...))
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-03-06 13:56:05 +01:00
|
|
|
size_t __ret;
|
Add __raw_visit and __raw_idx_visit, use INVOKE<R>
This change simplifies visitation for variants, by using INVOKE<R> for
the visit<R> form, and explicitly specifying the tag types for raw
visitation, instead of inferring them from the return types of the
lambda functions used as visitors.
* include/std/variant (__visit_with_index): Remove typedef.
(__deduce_visit_result): New tag type.
(__raw_visit, __raw_idx_visit): New helper functions for "raw"
visitation of possibly-valueless variants, forwarding to __do_visit
with the relevant tag type.
(_Variant_storage<false, _Types...>::_M_reset_impl): Use __raw_visit
and make lambda return void.
(__variant_construct): Likewise.
(_Copy_assign_base::operator=, _Move_assign_base::operator=): Use
__raw_idx_visit and make lambda return void.
(_Multi_array::__untag_result): Add metafunction to check the function
pointer type for a tag type that dictates the kind of visitation.
(_Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...>):
Use decltype(auto) instead of tagged function pointer type.
(__gen_vtable_impl): Remove bool non-type parameter and unused
_Variant_tuple parameter.
(__gen_vtable_impl::__visit_invoke_impl): Remove.
(__gen_vtable_impl::__do_visit_invoke): Remove.
(__gen_vtable_impl::__do_visit_invoke_r): Remove.
(__gen_vtable_impl::__visit_invoke): Use if-constexpr and __invoke_r
for the visit<R> case, rather than dispatching to separate functions.
(_VARIANT_RELATION_FUNCTION_TEMPLATE): Use __raw_idx_visit and make
lambda return void.
(variant::swap): Likewise.
(__do_visit): Replace two non-type template parameters with a single
type parameter, so that the caller must specify the visitor's return
type (or one of the tag types).
(visit): Deduce a return type from the visitor and use the
__deduce_visit_result tag to enforce that all overloads return the
same type.
(visit<R>): Call __do_visit<R> with explicit result type.
(__variant_hash_call_base_impl::operator()): Use __raw_visit and make
lambda return void.
From-SVN: r271182
2019-05-14 18:46:07 +02:00
|
|
|
__detail::__variant::__raw_visit(
|
|
|
|
[&__t, &__ret](auto&& __t_mem) mutable
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
2019-03-06 13:56:05 +01:00
|
|
|
using _Type = __remove_cvref_t<decltype(__t_mem)>;
|
|
|
|
if constexpr (!is_same_v<_Type,
|
|
|
|
__detail::__variant::__variant_cookie>)
|
|
|
|
__ret = std::hash<size_t>{}(__t.index())
|
|
|
|
+ std::hash<_Type>{}(__t_mem);
|
|
|
|
else
|
|
|
|
__ret = std::hash<size_t>{}(__t.index());
|
|
|
|
}, __t);
|
|
|
|
return __ret;
|
2016-08-18 22:31:26 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-21 16:38:23 +01:00
|
|
|
template<typename... _Types>
|
|
|
|
struct __variant_hash_call_base_impl<false, _Types...> {};
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
using __variant_hash_call_base =
|
|
|
|
__variant_hash_call_base_impl<(__poison_hash<remove_const_t<_Types>>::
|
|
|
|
__enable_hash_call &&...), _Types...>;
|
|
|
|
|
|
|
|
template<typename... _Types>
|
|
|
|
struct hash<variant<_Types...>>
|
|
|
|
: private __detail::__variant::_Variant_hash_base<
|
2017-07-23 10:41:35 +02:00
|
|
|
variant<_Types...>, std::index_sequence_for<_Types...>>,
|
2017-01-21 16:38:23 +01:00
|
|
|
public __variant_hash_call_base<_Types...>
|
|
|
|
{
|
2017-09-20 18:34:42 +02:00
|
|
|
using result_type [[__deprecated__]] = size_t;
|
|
|
|
using argument_type [[__deprecated__]] = variant<_Types...>;
|
2017-01-21 16:38:23 +01:00
|
|
|
};
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
template<>
|
|
|
|
struct hash<monostate>
|
|
|
|
{
|
2017-09-20 18:34:42 +02:00
|
|
|
using result_type [[__deprecated__]] = size_t;
|
|
|
|
using argument_type [[__deprecated__]] = monostate;
|
2016-08-18 22:31:26 +02:00
|
|
|
|
|
|
|
size_t
|
2019-06-12 16:52:09 +02:00
|
|
|
operator()(const monostate&) const noexcept
|
2016-08-18 22:31:26 +02:00
|
|
|
{
|
|
|
|
constexpr size_t __magic_monostate_hash = -7777;
|
|
|
|
return __magic_monostate_hash;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-09-20 18:34:42 +02:00
|
|
|
template<typename... _Types>
|
|
|
|
struct __is_fast_hash<hash<variant<_Types...>>>
|
|
|
|
: bool_constant<(__is_fast_hash<_Types>::value && ...)>
|
|
|
|
{ };
|
|
|
|
|
2016-08-18 22:31:26 +02:00
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
|
|
} // namespace std
|
|
|
|
|
|
|
|
#endif // C++17
|
|
|
|
|
|
|
|
#endif // _GLIBCXX_VARIANT
|