Add noexcept-specifier to std::apply and std::make_from_tuple

When unpacking a std::tuple we know that the std::get calls are
noexcept, so only the invocation (for std::apply) and construction (for
std::make_from_tuple) can throw.

We also know the std::get calls won't throw for a std::array, but this
patch doesn't specialize the variable template for std::array. For an
arbitrary tuple-like type we don't know if the std::get calls will
throw, and so just use a potentially-throwing noexcept-specifier.

	* include/std/tuple (__unpack_std_tuple): New variable template and
	partial specializations.
	(apply, make_from_tuple): Add noexcept-specifier.
	* testsuite/20_util/tuple/apply/2.cc: New test.
	* testsuite/20_util/tuple/make_from_tuple/2.cc: New test.

From-SVN: r274312
This commit is contained in:
Jonathan Wakely 2019-08-12 15:54:12 +01:00 committed by Jonathan Wakely
parent b0dffed9da
commit 6fd4b25b50
4 changed files with 159 additions and 0 deletions

View File

@ -1,3 +1,11 @@
2019-08-12 Jonathan Wakely <jwakely@redhat.com>
* include/std/tuple (__unpack_std_tuple): New variable template and
partial specializations.
(apply, make_from_tuple): Add noexcept-specifier.
* testsuite/20_util/tuple/apply/2.cc: New test.
* testsuite/20_util/tuple/make_from_tuple/2.cc: New test.
2019-08-09 Corentin Gay <gay@adacore.com>
* testsuite/ext/random/beta_distribution/operators/serialize.cc,

View File

@ -1591,6 +1591,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
#if __cplusplus >= 201703L
// Unpack a std::tuple into a type trait and use its value.
// For cv std::tuple<_Up> the result is _Trait<_Tp, cv _Up...>::value.
// For cv std::tuple<_Up>& the result is _Trait<_Tp, cv _Up&...>::value.
// Otherwise the result is false (because we don't know if std::get throws).
template<template<typename...> class _Trait, typename _Tp, typename _Tuple>
inline constexpr bool __unpack_std_tuple = false;
template<template<typename...> class _Trait, typename _Tp, typename... _Up>
inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>>
= _Trait<_Tp, _Up...>::value;
template<template<typename...> class _Trait, typename _Tp, typename... _Up>
inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>&>
= _Trait<_Tp, _Up&...>::value;
template<template<typename...> class _Trait, typename _Tp, typename... _Up>
inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>>
= _Trait<_Tp, const _Up...>::value;
template<template<typename...> class _Trait, typename _Tp, typename... _Up>
inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>&>
= _Trait<_Tp, const _Up&...>::value;
# define __cpp_lib_apply 201603
template <typename _Fn, typename _Tuple, size_t... _Idx>
@ -1604,6 +1628,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Fn, typename _Tuple>
constexpr decltype(auto)
apply(_Fn&& __f, _Tuple&& __t)
noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>)
{
using _Indices
= make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>;
@ -1622,6 +1647,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp, typename _Tuple>
constexpr _Tp
make_from_tuple(_Tuple&& __t)
noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>)
{
return __make_from_tuple_impl<_Tp>(
std::forward<_Tuple>(__t),

View File

@ -0,0 +1,62 @@
// Copyright (C) 2019 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
// Test noexcept-specifier on std::apply
#include <tuple>
using std::tuple;
using std::declval;
void f1();
static_assert( !noexcept(apply(f1, declval<tuple<>>())) );
static_assert( !noexcept(apply(f1, declval<tuple<>&>())) );
static_assert( !noexcept(apply(f1, declval<const tuple<>>())) );
static_assert( !noexcept(apply(f1, declval<const tuple<>&>())) );
void f2() noexcept;
static_assert( noexcept(apply(f2, declval<tuple<>>())) );
static_assert( noexcept(apply(f2, declval<tuple<>&>())) );
static_assert( noexcept(apply(f2, declval<const tuple<>>())) );
static_assert( noexcept(apply(f2, declval<const tuple<>&>())) );
struct F3 {
void operator()(int&);
void operator()(int&&) noexcept;
void operator()(const int&) noexcept;
void operator()(const int&&);
} f3;
static_assert( noexcept(apply(f3, declval<tuple<int>>())) );
static_assert( !noexcept(apply(f3, declval<tuple<int>&>())) );
static_assert( !noexcept(apply(f3, declval<const tuple<int>>())) );
static_assert( noexcept(apply(f3, declval<const tuple<int>&>())) );
struct F4 {
void operator()(int&, const int&);
void operator()(int&&, int&&) noexcept;
} f4;
static_assert( noexcept(apply(f4, declval<tuple<int, int>>())) );
static_assert( !noexcept(apply(f4, declval<tuple<int, int>&>())) );
static_assert( !noexcept(apply(f4, declval<tuple<int&, const int>>())) );
static_assert( !noexcept(apply(f4, declval<tuple<int, const int>&>())) );

View File

@ -0,0 +1,63 @@
// Copyright (C) 2019 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
// Test noexcept-specifier on std::make_from_tuple
#include <tuple>
using std::make_from_tuple;
using std::tuple;
using std::declval;
struct T1 { T1(); };
static_assert( !noexcept(make_from_tuple<T1>(declval<tuple<>>())) );
static_assert( !noexcept(make_from_tuple<T1>(declval<tuple<>&>())) );
static_assert( !noexcept(make_from_tuple<T1>(declval<const tuple<>>())) );
static_assert( !noexcept(make_from_tuple<T1>(declval<const tuple<>&>())) );
struct T2 { };
static_assert( noexcept(make_from_tuple<T2>(declval<tuple<>>())) );
static_assert( noexcept(make_from_tuple<T2>(declval<tuple<>&>())) );
static_assert( noexcept(make_from_tuple<T2>(declval<const tuple<>>())) );
static_assert( noexcept(make_from_tuple<T2>(declval<const tuple<>&>())) );
struct T3 {
T3(int&);
T3(int&&) noexcept;
T3(const int&) noexcept;
T3(const int&&);
};
static_assert( noexcept(make_from_tuple<T3>(declval<tuple<int>>())) );
static_assert( !noexcept(make_from_tuple<T3>(declval<tuple<int>&>())) );
static_assert( !noexcept(make_from_tuple<T3>(declval<const tuple<int>>())) );
static_assert( noexcept(make_from_tuple<T3>(declval<const tuple<int>&>())) );
struct T4 {
T4(int&, const int&);
T4(int&&, int&&) noexcept;
};
static_assert( noexcept(make_from_tuple<T4>(declval<tuple<int, int>>())) );
static_assert( !noexcept(make_from_tuple<T4>(declval<tuple<int, int>&>())) );
static_assert( !noexcept(make_from_tuple<T4>(declval<tuple<int&, const int>>())) );
static_assert( !noexcept(make_from_tuple<T4>(declval<tuple<int, const int>&>())) );