mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 03:46:53 -05:00
Instantiating the __deduce_funcref function body for function pointers without arguments or member pointers with non-matching object types previously led to hard errors due to the formation of invalid types. The __deduce_funcref function is now adjusted to return void in such cases. The corresponding function_ref deduction guide is constrained to only match if the return type is not void, making it SFINAE friendly. PR libstdc++/121940 libstdc++-v3/ChangeLog: * include/bits/funcwrap.h (__polyfunc::__deduce_funcref): Return void for ill-formed constructs. (function_ref(nontype_t<__f>, _Tp&&)): Constrain on __deduce_funcref producing non-void results. * testsuite/20_util/function_ref/deduction.cc: Negative tests. Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
621 lines
18 KiB
C++
621 lines
18 KiB
C++
// Implementation of std::move_only_function, std::copyable_function
|
|
// and 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/funcwrap.h
|
|
* This is an internal header file, included by other library headers.
|
|
* Do not attempt to use it directly. @headername{functional}
|
|
*/
|
|
|
|
#ifndef _GLIBCXX_FUNCWRAP_H
|
|
#define _GLIBCXX_FUNCWRAP_H 1
|
|
|
|
#ifdef _GLIBCXX_SYSHDR
|
|
#pragma GCC system_header
|
|
#endif
|
|
|
|
#include <bits/version.h>
|
|
|
|
#if __glibcxx_move_only_function || __glibcxx_copyable_function || __glibcxx_function_ref
|
|
|
|
#include <bits/invoke.h>
|
|
#include <bits/utility.h>
|
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
/// @cond undocumented
|
|
template<typename _Tp>
|
|
inline constexpr bool __is_polymorphic_function_v = false;
|
|
|
|
namespace __polyfunc
|
|
{
|
|
union _Ptrs
|
|
{
|
|
const void* _M_obj;
|
|
void (*_M_func)();
|
|
};
|
|
|
|
template<typename _Tp>
|
|
[[__gnu__::__always_inline__]]
|
|
constexpr auto*
|
|
__cast_to(_Ptrs __ptrs) noexcept
|
|
{
|
|
using _Td = remove_reference_t<_Tp>;
|
|
if constexpr (is_function_v<_Td>)
|
|
return reinterpret_cast<_Td*>(__ptrs._M_func);
|
|
else if constexpr (is_const_v<_Td>)
|
|
return static_cast<_Td*>(__ptrs._M_obj);
|
|
else
|
|
return static_cast<_Td*>(const_cast<void*>(__ptrs._M_obj));
|
|
}
|
|
|
|
struct _Storage
|
|
{
|
|
void* _M_addr() noexcept { return &_M_bytes[0]; }
|
|
void const* _M_addr() const noexcept { return &_M_bytes[0]; }
|
|
|
|
template<typename _Tp>
|
|
static consteval bool
|
|
_S_stored_locally() noexcept
|
|
{
|
|
return sizeof(_Tp) <= sizeof(_Storage)
|
|
&& alignof(_Tp) <= alignof(_Storage)
|
|
&& is_nothrow_move_constructible_v<_Tp>;
|
|
}
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
static consteval bool
|
|
_S_nothrow_init() noexcept
|
|
{
|
|
if constexpr (_S_stored_locally<_Tp>())
|
|
return is_nothrow_constructible_v<_Tp, _Args...>;
|
|
return false;
|
|
}
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
void
|
|
_M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
|
|
{
|
|
if constexpr (is_function_v<remove_pointer_t<_Tp>>)
|
|
{
|
|
static_assert( sizeof...(__args) <= 1 );
|
|
// __args can have up to one element, returns nullptr if empty.
|
|
_Tp __func = (nullptr, ..., __args);
|
|
_M_ptrs._M_func = reinterpret_cast<void(*)()>(__func);
|
|
}
|
|
else if constexpr (!_S_stored_locally<_Tp>())
|
|
_M_ptrs._M_obj = new _Tp(std::forward<_Args>(__args)...);
|
|
else
|
|
::new (_M_addr()) _Tp(std::forward<_Args>(__args)...);
|
|
}
|
|
|
|
// We want to have enough space to store a simple delegate type.
|
|
struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
|
|
union {
|
|
_Ptrs _M_ptrs;
|
|
alignas(_Delegate) alignas(void(*)())
|
|
unsigned char _M_bytes[sizeof(_Delegate)];
|
|
};
|
|
};
|
|
|
|
template<bool _Noex, typename _Ret, typename... _Args>
|
|
struct _Base_invoker
|
|
{
|
|
using _Signature = _Ret(*)(_Args...) noexcept(_Noex);
|
|
|
|
using __storage_func_t = _Ret(*)(const _Storage&, _Args...) noexcept(_Noex);
|
|
template<typename _Tp>
|
|
static consteval __storage_func_t
|
|
_S_storage()
|
|
{ return &_S_call_storage<_Adjust_target<_Tp>>; }
|
|
|
|
using __ptrs_func_t = _Ret(*)(_Ptrs, _Args...) noexcept(_Noex);
|
|
template<typename _Tp>
|
|
static consteval __ptrs_func_t
|
|
_S_ptrs()
|
|
{ return &_S_call_ptrs<_Adjust_target<_Tp>>; }
|
|
|
|
#ifdef __glibcxx_function_ref // C++ >= 26
|
|
template<auto __fn>
|
|
static _Ret
|
|
_S_nttp(_Ptrs, _Args... __args) noexcept(_Noex)
|
|
{ return std::__invoke_r<_Ret>(__fn, std::forward<_Args>(__args)...); }
|
|
|
|
template<auto __fn, typename _Tp>
|
|
static _Ret
|
|
_S_bind_ptr(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
|
|
{
|
|
auto* __p = __polyfunc::__cast_to<_Tp>(__ptrs);
|
|
return std::__invoke_r<_Ret>(__fn, __p,
|
|
std::forward<_Args>(__args)...);
|
|
}
|
|
|
|
template<auto __fn, typename _Ref>
|
|
static _Ret
|
|
_S_bind_ref(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
|
|
{
|
|
auto* __p = __polyfunc::__cast_to<_Ref>(__ptrs);
|
|
return std::__invoke_r<_Ret>(__fn, static_cast<_Ref>(*__p),
|
|
std::forward<_Args>(__args)...);
|
|
}
|
|
#endif // __glibcxx_function_ref
|
|
|
|
private:
|
|
template<typename _Tp, typename _Td = remove_cvref_t<_Tp>>
|
|
using _Adjust_target =
|
|
__conditional_t<is_pointer_v<_Td> || is_member_pointer_v<_Td>, _Td, _Tp>;
|
|
|
|
template<typename _Tp>
|
|
static _Ret
|
|
_S_call_storage(const _Storage& __ref, _Args... __args) noexcept(_Noex)
|
|
{
|
|
_Ptrs __ptrs;
|
|
if constexpr (is_function_v<remove_pointer_t<_Tp>>)
|
|
__ptrs._M_func = __ref._M_ptrs._M_func;
|
|
else if constexpr (!_Storage::_S_stored_locally<remove_cvref_t<_Tp>>())
|
|
__ptrs._M_obj = __ref._M_ptrs._M_obj;
|
|
else
|
|
__ptrs._M_obj = __ref._M_addr();
|
|
return _S_call_ptrs<_Tp>(__ptrs, std::forward<_Args>(__args)...);
|
|
}
|
|
|
|
template<typename _Tp>
|
|
static _Ret
|
|
_S_call_ptrs(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
|
|
{
|
|
if constexpr (is_function_v<remove_pointer_t<_Tp>>)
|
|
return std::__invoke_r<_Ret>(reinterpret_cast<_Tp>(__ptrs._M_func),
|
|
std::forward<_Args>(__args)...);
|
|
else
|
|
{
|
|
auto* __p = __polyfunc::__cast_to<_Tp>(__ptrs);
|
|
return std::__invoke_r<_Ret>(static_cast<_Tp>(*__p),
|
|
std::forward<_Args>(__args)...);
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename _Tp>
|
|
consteval bool
|
|
__pass_by_value()
|
|
{
|
|
// n.b. sizeof(Incomplete&) is ill-formed for incomplete types,
|
|
// so we check is_reference_v first.
|
|
if constexpr (is_reference_v<_Tp> || is_scalar_v<_Tp>)
|
|
return true;
|
|
else
|
|
// n.b. we already asserted that types are complete in wrappers,
|
|
// avoid triggering additional errors from this function.
|
|
if constexpr (std::__is_complete_or_unbounded(__type_identity<_Tp>()))
|
|
if constexpr (sizeof(_Tp) <= 2 * sizeof(void*))
|
|
return is_trivially_move_constructible_v<_Tp>
|
|
&& is_trivially_destructible_v<_Tp>;
|
|
return false;
|
|
}
|
|
|
|
template<typename _Tp>
|
|
using __param_t = __conditional_t<__pass_by_value<_Tp>(), _Tp, _Tp&&>;
|
|
|
|
template<bool _Noex, typename _Ret, typename... _Args>
|
|
using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>;
|
|
|
|
template<typename _Func>
|
|
auto&
|
|
__invoker_of(_Func& __f) noexcept
|
|
{ return __f._M_invoke; }
|
|
|
|
template<typename _Func>
|
|
auto&
|
|
__base_of(_Func& __f) noexcept
|
|
{ return static_cast<__like_t<_Func&, typename _Func::_Base>>(__f); }
|
|
|
|
template<typename _Src, typename _Dst>
|
|
consteval bool
|
|
__is_invoker_convertible() noexcept
|
|
{
|
|
if constexpr (requires { typename _Src::_Signature; })
|
|
return is_convertible_v<typename _Src::_Signature,
|
|
typename _Dst::_Signature>;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
#if __glibcxx_move_only_function || __glibcxx_copyable_function
|
|
struct _Manager
|
|
{
|
|
enum class _Op
|
|
{
|
|
// saves address of entity in *__src to __target._M_ptrs,
|
|
_Address,
|
|
// moves entity stored in *__src to __target, __src becomes empty
|
|
_Move,
|
|
// copies entity stored in *__src to __target, supported only if
|
|
// _ProvideCopy is specified.
|
|
_Copy,
|
|
// destroys entity stored in __target, __src is ignoring
|
|
_Destroy,
|
|
};
|
|
|
|
// A function that performs operation __op on the __target and possibly __src.
|
|
using _Func = void (*)(_Op __op, _Storage& __target, const _Storage* __src);
|
|
|
|
// The no-op manager function for objects with no target.
|
|
static void _S_empty(_Op, _Storage&, const _Storage*) noexcept { }
|
|
|
|
template<bool _ProvideCopy, typename _Tp>
|
|
consteval static auto
|
|
_S_select()
|
|
{
|
|
if constexpr (is_function_v<remove_pointer_t<_Tp>>)
|
|
return &_S_func;
|
|
else if constexpr (!_Storage::_S_stored_locally<_Tp>())
|
|
return &_S_ptr<_ProvideCopy, _Tp>;
|
|
else if constexpr (is_trivially_copyable_v<_Tp>)
|
|
return &_S_trivial;
|
|
else
|
|
return &_S_local<_ProvideCopy, _Tp>;
|
|
}
|
|
|
|
private:
|
|
static void
|
|
_S_func(_Op __op, _Storage& __target, const _Storage* __src) noexcept
|
|
{
|
|
switch (__op)
|
|
{
|
|
case _Op::_Address:
|
|
case _Op::_Move:
|
|
case _Op::_Copy:
|
|
__target._M_ptrs._M_func = __src->_M_ptrs._M_func;
|
|
return;
|
|
case _Op::_Destroy:
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_S_trivial(_Op __op, _Storage& __target, const _Storage* __src) noexcept
|
|
{
|
|
switch (__op)
|
|
{
|
|
case _Op::_Address:
|
|
__target._M_ptrs._M_obj = __src->_M_addr();
|
|
return;
|
|
case _Op::_Move:
|
|
case _Op::_Copy:
|
|
// N.B. Creating _Storage starts lifetime of _M_bytes char array,
|
|
// that implicitly creates, amongst other, all possible trivially
|
|
// copyable objects, so we copy any object present in __src._M_bytes.
|
|
::new (&__target) _Storage(*__src);
|
|
return;
|
|
case _Op::_Destroy:
|
|
return;
|
|
}
|
|
}
|
|
|
|
template<bool _Provide_copy, typename _Tp>
|
|
static void
|
|
_S_local(_Op __op, _Storage& __target, const _Storage* __src)
|
|
noexcept(!_Provide_copy)
|
|
{
|
|
switch (__op)
|
|
{
|
|
case _Op::_Address:
|
|
__target._M_ptrs._M_obj = __src->_M_addr();
|
|
return;
|
|
case _Op::_Move:
|
|
{
|
|
_Tp* __obj = static_cast<_Tp*>(const_cast<void*>(__src->_M_addr()));
|
|
::new(__target._M_addr()) _Tp(std::move(*__obj));
|
|
__obj->~_Tp();
|
|
}
|
|
return;
|
|
case _Op::_Destroy:
|
|
static_cast<_Tp*>(__target._M_addr())->~_Tp();
|
|
return;
|
|
case _Op::_Copy:
|
|
if constexpr (_Provide_copy)
|
|
{
|
|
auto* __obj = static_cast<const _Tp*>(__src->_M_addr());
|
|
::new (__target._M_addr()) _Tp(*__obj);
|
|
return;
|
|
}
|
|
__builtin_unreachable();
|
|
}
|
|
}
|
|
|
|
template<bool _Provide_copy, typename _Tp>
|
|
static void
|
|
_S_ptr(_Op __op, _Storage& __target, const _Storage* __src)
|
|
noexcept(!_Provide_copy)
|
|
{
|
|
switch (__op)
|
|
{
|
|
case _Op::_Address:
|
|
case _Op::_Move:
|
|
__target._M_ptrs._M_obj = __src->_M_ptrs._M_obj;
|
|
return;
|
|
case _Op::_Destroy:
|
|
delete static_cast<const _Tp*>(__target._M_ptrs._M_obj);
|
|
return;
|
|
case _Op::_Copy:
|
|
if constexpr (_Provide_copy)
|
|
{
|
|
auto* __obj = static_cast<const _Tp*>(__src->_M_ptrs._M_obj);
|
|
__target._M_ptrs._M_obj = new _Tp(*__obj);
|
|
return;
|
|
}
|
|
__builtin_unreachable();
|
|
}
|
|
}
|
|
};
|
|
|
|
class _Mo_base
|
|
{
|
|
protected:
|
|
_Mo_base() noexcept
|
|
: _M_manage(_Manager::_S_empty)
|
|
{ }
|
|
|
|
_Mo_base(_Mo_base&& __x) noexcept
|
|
{ _M_move(__x); }
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
static consteval bool
|
|
_S_nothrow_init() noexcept
|
|
{ return _Storage::_S_nothrow_init<_Tp, _Args...>(); }
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
void
|
|
_M_init(_Args&&... __args)
|
|
noexcept(_S_nothrow_init<_Tp, _Args...>())
|
|
{
|
|
_M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
|
|
_M_manage = _Manager::_S_select<false, _Tp>();
|
|
}
|
|
|
|
void
|
|
_M_move(_Mo_base& __x) noexcept
|
|
{
|
|
using _Op = _Manager::_Op;
|
|
_M_manage = std::__exchange(__x._M_manage, _Manager::_S_empty);
|
|
_M_manage(_Op::_Move, _M_storage, &__x._M_storage);
|
|
}
|
|
|
|
_Mo_base&
|
|
operator=(_Mo_base&& __x) noexcept
|
|
{
|
|
_M_destroy();
|
|
_M_move(__x);
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
_M_reset() noexcept
|
|
{
|
|
_M_destroy();
|
|
_M_manage = _Manager::_S_empty;
|
|
}
|
|
|
|
void _M_destroy() noexcept
|
|
{ _M_manage(_Manager::_Op::_Destroy, _M_storage, nullptr); }
|
|
|
|
~_Mo_base()
|
|
{ _M_destroy(); }
|
|
|
|
void
|
|
swap(_Mo_base& __x) noexcept
|
|
{
|
|
using _Op = _Manager::_Op;
|
|
// Order of operations here is more efficient if __x is empty.
|
|
_Storage __s;
|
|
__x._M_manage(_Op::_Move, __s, &__x._M_storage);
|
|
_M_manage(_Op::_Move, __x._M_storage, &_M_storage);
|
|
__x._M_manage(_Op::_Move, _M_storage, &__s);
|
|
std::swap(_M_manage, __x._M_manage);
|
|
}
|
|
|
|
_Manager::_Func _M_manage;
|
|
_Storage _M_storage;
|
|
};
|
|
#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
|
|
} // namespace __polyfunc
|
|
/// @endcond
|
|
|
|
#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
|
|
template<typename... _Signature>
|
|
class move_only_function; // not defined
|
|
|
|
/// @cond undocumented
|
|
template<typename _Tp>
|
|
constexpr bool __is_polymorphic_function_v<move_only_function<_Tp>> = true;
|
|
|
|
namespace __detail::__variant
|
|
{
|
|
template<typename> struct _Never_valueless_alt; // see <variant>
|
|
|
|
// Provide the strong exception-safety guarantee when emplacing a
|
|
// move_only_function into a variant.
|
|
template<typename... _Signature>
|
|
struct _Never_valueless_alt<std::move_only_function<_Signature...>>
|
|
: true_type
|
|
{ };
|
|
} // namespace __detail::__variant
|
|
/// @endcond
|
|
#endif // __glibcxx_move_only_function
|
|
|
|
#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
|
|
/// @cond undocumented
|
|
namespace __polyfunc
|
|
{
|
|
class _Cpy_base : public _Mo_base
|
|
{
|
|
protected:
|
|
_Cpy_base() = default;
|
|
|
|
template<typename _Tp, typename... _Args>
|
|
void
|
|
_M_init(_Args&&... __args)
|
|
noexcept(_S_nothrow_init<_Tp, _Args...>())
|
|
{
|
|
_M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
|
|
_M_manage = _Manager::_S_select<true, _Tp>();
|
|
}
|
|
|
|
void
|
|
_M_copy(_Cpy_base const& __x)
|
|
{
|
|
using _Op = _Manager::_Op;
|
|
__x._M_manage(_Op::_Copy, _M_storage, &__x._M_storage);
|
|
_M_manage = __x._M_manage;
|
|
}
|
|
|
|
_Cpy_base(_Cpy_base&&) = default;
|
|
|
|
_Cpy_base(_Cpy_base const& __x)
|
|
{ _M_copy(__x); }
|
|
|
|
_Cpy_base&
|
|
operator=(_Cpy_base&&) = default;
|
|
|
|
_Cpy_base&
|
|
// Needs to use copy and swap for exception guarantees.
|
|
operator=(_Cpy_base const&) = delete;
|
|
};
|
|
} // namespace __polyfunc
|
|
/// @endcond
|
|
|
|
template<typename... _Signature>
|
|
class copyable_function; // not defined
|
|
|
|
template<typename _Tp>
|
|
constexpr bool __is_polymorphic_function_v<copyable_function<_Tp>> = true;
|
|
|
|
namespace __detail::__variant
|
|
{
|
|
template<typename> struct _Never_valueless_alt; // see <variant>
|
|
|
|
// Provide the strong exception-safety guarantee when emplacing a
|
|
// copyable_function into a variant.
|
|
template<typename... _Signature>
|
|
struct _Never_valueless_alt<std::copyable_function<_Signature...>>
|
|
: true_type
|
|
{ };
|
|
} // namespace __detail::__variant
|
|
#endif // __glibcxx_copyable_function
|
|
|
|
#ifdef __glibcxx_function_ref // C++ >= 26
|
|
/// @cond undocumented
|
|
namespace __polyfunc
|
|
{
|
|
template<typename _Sig>
|
|
struct __skip_first_arg;
|
|
|
|
// Additional partial specializations are defined in bits/funcref_impl.h
|
|
template<bool _Noex, typename _Ret, typename _Arg, typename... _Args>
|
|
struct __skip_first_arg<_Ret(*)(_Arg, _Args...) noexcept(_Noex)>
|
|
{ using type = _Ret(_Args...) noexcept(_Noex); };
|
|
|
|
// Returns a function pointer to signature to be used with function_ref, or void.
|
|
template<typename _Fn, typename _Tr>
|
|
consteval auto
|
|
__deduce_funcref()
|
|
{
|
|
if constexpr (is_member_object_pointer_v<_Fn>)
|
|
{
|
|
if constexpr (is_invocable_v<_Fn, _Tr>)
|
|
// TODO Consider reporting issue to make this noexcept
|
|
return static_cast<invoke_result_t<_Fn, _Tr>(*)()>(nullptr);
|
|
}
|
|
else if constexpr (requires { typename __skip_first_arg<_Fn>::type; })
|
|
return static_cast<__skip_first_arg<_Fn>::type*>(nullptr);
|
|
}
|
|
} // namespace __polyfunc
|
|
/// @endcond
|
|
|
|
template<typename... _Signature>
|
|
class function_ref; // not defined
|
|
|
|
template<typename _Fn>
|
|
requires is_function_v<_Fn>
|
|
function_ref(_Fn*) -> function_ref<_Fn>;
|
|
|
|
template<auto __f, class _Fn = remove_pointer_t<decltype(__f)>>
|
|
requires is_function_v<_Fn>
|
|
function_ref(nontype_t<__f>) -> function_ref<_Fn>;
|
|
|
|
template<auto __f, typename _Tp,
|
|
typename _SignaturePtr =
|
|
decltype(__polyfunc::__deduce_funcref<decltype(__f), _Tp&>())>
|
|
requires (!is_void_v<_SignaturePtr>)
|
|
function_ref(nontype_t<__f>, _Tp&&)
|
|
-> function_ref<remove_pointer_t<_SignaturePtr>>;
|
|
|
|
#endif // __glibcxx_function_ref
|
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace std
|
|
|
|
#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
|
|
#include "mofunc_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#include "mofunc_impl.h"
|
|
#define _GLIBCXX_MOF_REF &
|
|
#include "mofunc_impl.h"
|
|
#define _GLIBCXX_MOF_REF &&
|
|
#include "mofunc_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#define _GLIBCXX_MOF_REF &
|
|
#include "mofunc_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#define _GLIBCXX_MOF_REF &&
|
|
#include "mofunc_impl.h"
|
|
#endif // __glibcxx_move_only_function
|
|
|
|
#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
|
|
#include "cpyfunc_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#include "cpyfunc_impl.h"
|
|
#define _GLIBCXX_MOF_REF &
|
|
#include "cpyfunc_impl.h"
|
|
#define _GLIBCXX_MOF_REF &&
|
|
#include "cpyfunc_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#define _GLIBCXX_MOF_REF &
|
|
#include "cpyfunc_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#define _GLIBCXX_MOF_REF &&
|
|
#include "cpyfunc_impl.h"
|
|
#endif // __glibcxx_copyable_function
|
|
|
|
#ifdef __glibcxx_function_ref // C++ >= 26
|
|
#include "funcref_impl.h"
|
|
#define _GLIBCXX_MOF_CV const
|
|
#include "funcref_impl.h"
|
|
#endif // __glibcxx_function_ref
|
|
|
|
#endif // move_only_function || copyable_function || function_ref
|
|
#endif // _GLIBCXX_FUNCWRAP_H
|