To avoid a circular dependency between <tuple> and <functional> I've moved std::__invoke to its own header.
In order to use std::__invoke in std::apply it needs to be constexpr, which is easy, but the standard says that std::invoke isn't constexpr. So we have to intentionally disallow std::invoke in constant expressions even though it's implemented purely in terms of a constexpr function. Expect a ballot comment about that. This also fixes a bug in the exception specifications of std::__invoke and std::invoke, where the function type used as the template argument to __is_nothrow_callable would have decayed its argument types, so we need && there to prevent that. * doc/xml/manual/status_cxx2017.xml: Add missing LFTSv2 features. * doc/html/manual/status.html: Regenerate. * include/Makefile.am: Add new header. * include/Makefile.in: Regenerate. * include/bits/invoke.h: New header. (__invoke): Make constexpr. Add && to types in exception specification. * include/experimental/tuple (apply, __apply_impl): Fix non-reserved names. Include <bits/invoke.h> and use std::__invoke. * include/std/functional (__invfwd, __invoke_impl, __invoke): Move to new header. (invoke): Add && to types in exception specification. * include/std/tuple (apply, __apply_impl): Define for C++17. * testsuite/20_util/tuple/apply/1.cc: New test. * testsuite/20_util/tuple/element_access/get_neg.cc: Adjust dg-error lineno. Tested powerpc64-linux, committed to trunk.
commit 031d50fec36dd04c1e086ab7060d497a441f0d8a Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Aug 5 17:27:46 2016 +0100 Add std::apply for C++17 * doc/xml/manual/status_cxx2017.xml: Add missing LFTSv2 features. * doc/html/manual/status.html: Regenerate. * include/Makefile.am: Add new header. * include/Makefile.in: Regenerate. * include/bits/invoke.h: New header. (__invoke): Make constexpr. Add && to types in exception specification. * include/experimental/tuple (apply, __apply_impl): Fix non-reserved names. Include <bits/invoke.h> and use std::__invoke. * include/std/functional (__invfwd, __invoke_impl, __invoke): Move to new header. (invoke): Add && to types in exception specification. * include/std/tuple (apply, __apply_impl): Define for C++17. * testsuite/20_util/tuple/apply/1.cc: New test. * testsuite/20_util/tuple/element_access/get_neg.cc: Adjust dg-error lineno. diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index 02aec25..55e3ff5 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml @@ -149,6 +149,41 @@ Feature-testing recommendations for C++</link>. </row> <row> + <entry> Library Fundamentals V1 TS Components: <code>apply</code> </entry> + <entry> + <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html"> + P0220R1 + </link> + </entry> + <entry align="center"> 7 </entry> + <entry> <code>__cpp_lib_apply >= 201603</code> </entry> + </row> + + <row> + <?dbhtml bgcolor="#C8B0B0" ?> + <entry> Library Fundamentals V1 TS Components: <code>shared_ptr<T[]></code> </entry> + <entry> + <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html"> + P0220R1 + </link> + </entry> + <entry align="center"> No </entry> + <entry> <code>__cpp_lib_shared_ptr_arrays >= 201603</code> </entry> + </row> + + <row> + <?dbhtml bgcolor="#C8B0B0" ?> + <entry> Library Fundamentals V1 TS Components: Searchers </entry> + <entry> + <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html"> + P0220R1 + </link> + </entry> + <entry align="center"> No </entry> + <entry> <code>__cpp_lib_boyer_moore_searcher >= 201603</code> </entry> + </row> + + <row> <entry> Constant View: A proposal for a <code>std::as_const</code> helper function template </entry> <entry> <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href=""> diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index e2c4f63..ea992f0 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -112,6 +112,7 @@ bits_headers = \ ${bits_srcdir}/hashtable.h \ ${bits_srcdir}/hashtable_policy.h \ ${bits_srcdir}/indirect_array.h \ + ${bits_srcdir}/invoke.h \ ${bits_srcdir}/ios_base.h \ ${bits_srcdir}/istream.tcc \ ${bits_srcdir}/list.tcc \ diff --git a/libstdc++-v3/include/bits/invoke.h b/libstdc++-v3/include/bits/invoke.h new file mode 100644 index 0000000..60405b5 --- /dev/null +++ b/libstdc++-v3/include/bits/invoke.h @@ -0,0 +1,104 @@ +// Implementation of INVOKE -*- C++ -*- + +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// 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 include/bits/invoke.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _GLIBCXX_INVOKE_H +#define _GLIBCXX_INVOKE_H 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include <bits/c++0x_warning.h> +#else + +#include <type_traits> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + + // Used by __invoke_impl instead of std::forward<_Tp> so that a + // reference_wrapper is converted to an lvalue-reference. + template<typename _Tp, typename _Up = typename __inv_unwrap<_Tp>::type> + constexpr _Up&& + __invfwd(typename remove_reference<_Tp>::type& __t) noexcept + { return static_cast<_Up&&>(__t); } + + template<typename _Res, typename _Fn, typename... _Args> + constexpr _Res + __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) + { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); } + + template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> + constexpr _Res + __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); } + + template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> + constexpr _Res + __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + { + return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...); + } + + template<typename _Res, typename _MemPtr, typename _Tp> + constexpr _Res + __invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t) + { return __invfwd<_Tp>(__t).*__f; } + + template<typename _Res, typename _MemPtr, typename _Tp> + constexpr _Res + __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t) + { return (*std::forward<_Tp>(__t)).*__f; } + + /// Invoke a callable object. + template<typename _Callable, typename... _Args> + constexpr typename result_of<_Callable&&(_Args&&...)>::type + __invoke(_Callable&& __fn, _Args&&... __args) + noexcept(__is_nothrow_callable<_Callable(_Args&&...)>::value) + { + using __result_of = result_of<_Callable&&(_Args&&...)>; + using __type = typename __result_of::type; + using __tag = typename __result_of::__invoke_type; + return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), + std::forward<_Args>(__args)...); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++11 + +#endif // _GLIBCXX_INVOKE_H diff --git a/libstdc++-v3/include/experimental/tuple b/libstdc++-v3/include/experimental/tuple index 81e91bd..bfa1ed1 100644 --- a/libstdc++-v3/include/experimental/tuple +++ b/libstdc++-v3/include/experimental/tuple @@ -36,7 +36,7 @@ #else #include <tuple> -#include <functional> +#include <bits/invoke.h> namespace std _GLIBCXX_VISIBILITY(default) { @@ -54,20 +54,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Fn, typename _Tuple, std::size_t... _Idx> constexpr decltype(auto) - __apply_impl(_Fn&& f, _Tuple&& t, std::index_sequence<_Idx...>) + __apply_impl(_Fn&& __f, _Tuple&& __t, std::index_sequence<_Idx...>) { - using _Wrap = _Maybe_wrap_member_pointer<decay_t<_Fn>>; - return _Wrap::__do_wrap(std::forward<_Fn>(f))( - std::get<_Idx>(std::forward<_Tuple>(t))...); + return std::__invoke(std::forward<_Fn>(__f), + std::get<_Idx>(std::forward<_Tuple>(__t))...); } template <typename _Fn, typename _Tuple> constexpr decltype(auto) - apply(_Fn&& f, _Tuple&& t) + apply(_Fn&& __f, _Tuple&& __t) { using _Indices = - std::make_index_sequence<std::tuple_size<std::decay_t<_Tuple>>::value>; - return __apply_impl(std::forward<_Fn>(f), std::forward<_Tuple>(t), + std::make_index_sequence<tuple_size_v<std::decay_t<_Tuple>>>; + return __apply_impl(std::forward<_Fn>(__f), std::forward<_Tuple>(__t), _Indices{}); } diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 4ca32c3..1de914e 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -56,6 +56,7 @@ #include <type_traits> #include <bits/functexcept.h> #include <bits/functional_hash.h> +#include <bits/invoke.h> namespace std _GLIBCXX_VISIBILITY(default) { @@ -184,55 +185,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Weak_result_type_impl<typename remove_cv<_Functor>::type> { }; - // Used by __invoke_impl instead of std::forward<_Tp> so that a - // reference_wrapper is converted to an lvalue-reference. - template<typename _Tp, typename _Up = typename __inv_unwrap<_Tp>::type> - inline _Up&& - __invfwd(typename remove_reference<_Tp>::type& __t) noexcept - { return static_cast<_Up&&>(__t); } - - template<typename _Res, typename _Fn, typename... _Args> - inline _Res - __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) - { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); } - - template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> - inline _Res - __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, - _Args&&... __args) - { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); } - - template<typename _Res, typename _MemFun, typename _Tp, typename... _Args> - inline _Res - __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t, - _Args&&... __args) - { - return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...); - } - - template<typename _Res, typename _MemPtr, typename _Tp> - inline _Res - __invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t) - { return __invfwd<_Tp>(__t).*__f; } - - template<typename _Res, typename _MemPtr, typename _Tp> - inline _Res - __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t) - { return (*std::forward<_Tp>(__t)).*__f; } - - /// Invoke a callable object. - template<typename _Callable, typename... _Args> - inline typename result_of<_Callable&&(_Args&&...)>::type - __invoke(_Callable&& __fn, _Args&&... __args) - noexcept(__is_nothrow_callable<_Callable(_Args...)>::value) - { - using __result_of = result_of<_Callable&&(_Args&&...)>; - using __type = typename __result_of::type; - using __tag = typename __result_of::__invoke_type; - return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), - std::forward<_Args>(__args)...); - } - #if __cplusplus > 201402L # define __cpp_lib_invoke 201411 @@ -240,7 +192,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Callable, typename... _Args> inline result_of_t<_Callable&&(_Args&&...)> invoke(_Callable&& __fn, _Args&&... __args) - noexcept(is_nothrow_callable_v<_Callable(_Args...)>) + noexcept(is_nothrow_callable_v<_Callable(_Args&&...)>) { return std::__invoke(std::forward<_Callable>(__fn), std::forward<_Args>(__args)...); diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 484cb48..b9074cb 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -38,6 +38,7 @@ #include <utility> #include <array> #include <bits/uses_allocator.h> +#include <bits/invoke.h> namespace std _GLIBCXX_VISIBILITY(default) { @@ -1635,6 +1636,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...) { } +#if __cplusplus > 201402L +# define __cpp_lib_apply 201603 + + template <typename _Fn, typename _Tuple, size_t... _Idx> + constexpr decltype(auto) + __apply_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Idx...>) + { + return std::__invoke(std::forward<_Fn>(__f), + std::get<_Idx>(std::forward<_Tuple>(__t))...); + } + + template <typename _Fn, typename _Tuple> + constexpr decltype(auto) + apply(_Fn&& __f, _Tuple&& __t) + { + using _Indices = make_index_sequence<tuple_size_v<decay_t<_Tuple>>>; + return __apply_impl(std::forward<_Fn>(__f), std::forward<_Tuple>(__t), + _Indices{}); + } +#endif // C++17 + /// @} _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/20_util/tuple/apply/1.cc b/libstdc++-v3/testsuite/20_util/tuple/apply/1.cc new file mode 100644 index 0000000..c12309c --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/apply/1.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2014-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a 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" } + +#include <tuple> +#include <testsuite_hooks.h> + +#if __cpp_lib_apply < 201603 +# error "__cpp_lib_apply < 201603" +#endif + +void +test01() +{ + auto t = std::make_tuple(1, '2', 3.0); + std::apply( [&](int& i, char& c, double& d) { + VERIFY(&i == &std::get<int>(t)); + VERIFY(&c == &std::get<char>(t)); + VERIFY(&d == &std::get<double>(t)); + }, t); +} + +constexpr int func(int i, int j) { return i + j; } + +void +test02() +{ + constexpr auto t = std::make_tuple(1, 2); + constexpr int i = std::apply(func, t); + VERIFY( i == 3 ); +} + +struct F +{ + int f(int i, int j) const { return i + j; } +}; + +void +test03() +{ + auto t = std::make_tuple(F{}, 1, 2); + int r = std::apply(&F::f, t); + VERIFY( r == 3 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc index 95ff697..5bcf576 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc @@ -17,7 +17,7 @@ // { dg-options "-fno-show-column" } // { dg-do compile { target c++14 } } -// { dg-error "in range" "" { target *-*-* } 1279 } +// { dg-error "in range" "" { target *-*-* } 1280 } #include <tuple>