mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 23:25:24 +02:00
This implements P3948R1: constant_wrapper is the only tool needed for passing constant expressions via function arguments. This changes function_ref from nontype_t to constant_wrapper and implements the ambiguity check (static_asert in function_ref from constant_wrapper constructor). In addition to P3948R1 this also includes the (forgotten) deduction guide changes suggested in the draft PR [1]. [1] https://github.com/cplusplus/draft/pull/8878 libstdc++-v3/ChangeLog: * include/bits/funcref_impl.h (function_ref::function_ref): Change nontype_t parameter to constant_wrapper, and adjust accordingly. Add static_assert detecting ambigous semantics. (function_ref::operator=): Detect constant_wrapper rather than nontype_t. * include/bits/funcwrap.h (function_ref): Change nontype_t parameter to constant_wrapper in deduction guides. * include/bits/utility.h (std::nontype_t, std::nontype) (std::__is_nontype_v): Remove. (std::__is_constant_wrapper_v): Define. * src/c++23/std.cc.in (std::nontype_t, std::nontype): Remove exports. * testsuite/20_util/function_ref/cw_cons_neg.cc: New tests for ambiguity check. * testsuite/20_util/function_ref/assign.cc: Replace nontype_t with constant_wrapper and nontype with std::cw. * testsuite/20_util/function_ref/call.cc: Likewise. * testsuite/20_util/function_ref/cons.cc: Likewise. * testsuite/20_util/function_ref/cons_neg.cc: Likewise. * testsuite/20_util/function_ref/dangling.cc: Likewise. * testsuite/20_util/function_ref/deduction.cc: Likewise. * testsuite/20_util/function_ref/mutation.cc: Likewise. Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com> Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Matthias Kretz <m.kretz@gsi.de> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
227 lines
8.1 KiB
C++
227 lines
8.1 KiB
C++
// Implementation of std::function_ref -*- C++ -*-
|
|
|
|
// Copyright The GNU Toolchain Authors.
|
|
//
|
|
// 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/funcref_impl.h
|
|
* This is an internal header file, included by other library headers.
|
|
* Do not attempt to use it directly. @headername{functional}
|
|
*/
|
|
|
|
#ifndef _GLIBCXX_MOF_CV
|
|
# define _GLIBCXX_MOF_CV
|
|
#endif
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/// @cond undocumented
|
|
namespace __polyfunc
|
|
{
|
|
template<bool _Noex, typename _Ret, typename _Class, typename... _Args>
|
|
struct __skip_first_arg<_Ret(_Class::*)(_Args...) _GLIBCXX_MOF_CV
|
|
noexcept(_Noex)>
|
|
{ using type = _Ret(_Args...) noexcept(_Noex); };
|
|
|
|
template<bool _Noex, typename _Ret, typename _Class, typename... _Args>
|
|
struct __skip_first_arg<_Ret(_Class::*)(_Args...) _GLIBCXX_MOF_CV&
|
|
noexcept(_Noex)>
|
|
{ using type = _Ret(_Args...) noexcept(_Noex); };
|
|
} // namespace __polyfunc
|
|
/// @endcond
|
|
|
|
/**
|
|
* @brief Non-owning polymorphic function wrapper.
|
|
* @ingroup functors
|
|
* @since C++26
|
|
* @headerfile functional
|
|
*
|
|
* The `std::function_ref` class template is a non-owning call wrapper,
|
|
* that refers to a bound object. Using function_ref outside of the lifetime
|
|
* of the bound object has undefined behavior.
|
|
*
|
|
* It supports const-qualification and no-throw guarantees. The
|
|
* qualifications and exception-specification of the signature are respected
|
|
* when invoking the reference function.
|
|
*/
|
|
template<typename _Res, typename... _ArgTypes, bool _Noex>
|
|
class function_ref<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
|
|
noexcept(_Noex)>
|
|
{
|
|
static_assert(
|
|
(std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
|
|
"each parameter type must be a complete class");
|
|
|
|
using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
|
|
using _Signature = _Invoker::_Signature;
|
|
|
|
// [func.wrap.ref.ctor]/1 is-invokable-using
|
|
template<typename... _Tps>
|
|
static constexpr bool __is_invocable_using
|
|
= __conditional_t<_Noex,
|
|
is_nothrow_invocable_r<_Res, _Tps..., _ArgTypes...>,
|
|
is_invocable_r<_Res, _Tps..., _ArgTypes...>>::value;
|
|
|
|
public:
|
|
/// Target and bound object is function pointed by parameter.
|
|
template<typename _Fn>
|
|
requires is_function_v<_Fn> && __is_invocable_using<_Fn*>
|
|
function_ref(_Fn* __fn) noexcept
|
|
{
|
|
__glibcxx_assert(__fn != nullptr);
|
|
_M_invoke = _Invoker::template _S_ptrs<_Fn*>();
|
|
_M_init(__fn);
|
|
}
|
|
|
|
/// Target and bound object is object referenced by parameter.
|
|
template<typename _Fn, typename _Vt = remove_reference_t<_Fn>>
|
|
requires (!is_same_v<remove_cv_t<_Vt>, function_ref>)
|
|
&& (!is_member_pointer_v<_Vt>)
|
|
// We deviate from standard by having this condition, that forces
|
|
// function references to use _Fn* constructors. This simplies
|
|
// implementation and provide better diagnostic when used in
|
|
// constant expression (above constructor is not constexpr).
|
|
&& (!is_function_v<_Vt>)
|
|
&& __is_invocable_using<_Vt _GLIBCXX_MOF_CV&>
|
|
constexpr
|
|
function_ref(_Fn&& __f) noexcept
|
|
{
|
|
using _Fd = remove_cv_t<_Vt>;
|
|
if constexpr (__is_std_op_wrapper<_Fd>)
|
|
{
|
|
_M_invoke = _Invoker::template _S_nttp<_Fd{}>;
|
|
_M_ptrs._M_obj = nullptr;
|
|
}
|
|
else if constexpr (requires (_ArgTypes&&... __args) {
|
|
_Fd::operator()(std::forward<_ArgTypes>(__args)...);
|
|
})
|
|
{
|
|
_M_invoke = _Invoker::template _S_static<_Fd>;
|
|
_M_ptrs._M_obj = nullptr;
|
|
}
|
|
else
|
|
{
|
|
_M_invoke = _Invoker::template _S_ptrs<_Vt _GLIBCXX_MOF_CV&>();
|
|
_M_init(std::addressof(__f));
|
|
}
|
|
}
|
|
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
// 4256. Incorrect constrains for function_ref constructors from nontype
|
|
/// Target object is __fn. There is no bound object.
|
|
template<auto __cwfn, typename _Fn>
|
|
requires __is_invocable_using<const _Fn&>
|
|
constexpr
|
|
function_ref(constant_wrapper<__cwfn, _Fn>) noexcept
|
|
{
|
|
constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value;
|
|
if constexpr (sizeof...(_ArgTypes) > 0)
|
|
if constexpr ((... && _ConstExprParam<remove_cvref_t<_ArgTypes>>))
|
|
static_assert(!requires {
|
|
typename constant_wrapper<
|
|
std::__invoke(__fn, remove_cvref_t<_ArgTypes>::value...)>;
|
|
}, "cw<fn>(args...) should be equivalent to fn(args...)");
|
|
|
|
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
|
|
static_assert(__fn != nullptr);
|
|
|
|
_M_invoke = &_Invoker::template _S_nttp<__fn>;
|
|
_M_ptrs._M_obj = nullptr;
|
|
}
|
|
|
|
/// Target object is equivalent to std::bind_front<_fn>(std::ref(__ref)).
|
|
/// Bound object is object referenced by second parameter.
|
|
template<auto __cwfn, typename _Fn, typename _Up,
|
|
typename _Td = remove_reference_t<_Up>>
|
|
requires (!is_rvalue_reference_v<_Up&&>)
|
|
&& __is_invocable_using<const _Fn&, _Td _GLIBCXX_MOF_CV&>
|
|
constexpr
|
|
function_ref(constant_wrapper<__cwfn, _Fn>, _Up&& __ref) noexcept
|
|
{
|
|
constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value;
|
|
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
|
|
static_assert(__fn != nullptr);
|
|
|
|
if constexpr (is_member_pointer_v<_Fn>
|
|
&& same_as<_Td, typename __inv_unwrap<_Td>::type>)
|
|
// N.B. invoking member pointer on lvalue produces the same effects,
|
|
// as invoking it on pointer to that lvalue.
|
|
_M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td _GLIBCXX_MOF_CV>;
|
|
else
|
|
_M_invoke = &_Invoker::template _S_bind_ref<__fn, _Td _GLIBCXX_MOF_CV&>;
|
|
_M_init(std::addressof(__ref));
|
|
}
|
|
|
|
/// Target object is equivalent to std::bind_front<_fn>(__ptr).
|
|
/// Bound object is object pointed by second parameter (if any).
|
|
template< auto __cwfn, typename _Fn, typename _Td>
|
|
requires __is_invocable_using<const _Fn&, _Td _GLIBCXX_MOF_CV*>
|
|
constexpr
|
|
function_ref(constant_wrapper<__cwfn, _Fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept
|
|
{
|
|
constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value;
|
|
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
|
|
static_assert(__fn != nullptr);
|
|
if constexpr (is_member_pointer_v<_Fn>)
|
|
__glibcxx_assert(__ptr != nullptr);
|
|
|
|
_M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td _GLIBCXX_MOF_CV>;
|
|
_M_init(__ptr);
|
|
}
|
|
|
|
template<typename _Tp>
|
|
requires (!is_same_v<_Tp, function_ref>) && (!is_pointer_v<_Tp>)
|
|
&& (!__is_constant_wrapper_v<_Tp>)
|
|
function_ref&
|
|
operator=(_Tp) = delete;
|
|
|
|
/** Invoke the target object.
|
|
*
|
|
* The bound object will be invoked using the supplied arguments,
|
|
* and as const or non-const, as dictated by the template arguments
|
|
* of the `function_ref` specialization.
|
|
*/
|
|
_Res
|
|
operator()(_ArgTypes... __args) const noexcept(_Noex)
|
|
{ return _M_invoke(_M_ptrs, std::forward<_ArgTypes>(__args)...); }
|
|
|
|
private:
|
|
template<typename _Tp>
|
|
constexpr void
|
|
_M_init(_Tp* __ptr) noexcept
|
|
{
|
|
if constexpr (is_function_v<_Tp>)
|
|
_M_ptrs._M_func = reinterpret_cast<void(*)()>(__ptr);
|
|
else
|
|
_M_ptrs._M_obj = __ptr;
|
|
}
|
|
|
|
typename _Invoker::__ptrs_func_t _M_invoke;
|
|
__polyfunc::_Ptrs _M_ptrs;
|
|
};
|
|
|
|
#undef _GLIBCXX_MOF_CV
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace std
|