3005 lines
101 KiB
C++
3005 lines
101 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Copyright 2025 Bloomberg Finance L.P.
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP_META
|
|
#define _LIBCPP_META
|
|
|
|
/*
|
|
meta synopsis
|
|
|
|
// C++2c
|
|
namespace std
|
|
{
|
|
namespace meta
|
|
{
|
|
inline namespace reflection_v2
|
|
{
|
|
|
|
// std::meta::info
|
|
using info = decltype(^^int);
|
|
|
|
// concept reflection_range
|
|
template <typename R>
|
|
concept reflection_range = see below;
|
|
|
|
// name and location
|
|
consteval auto identifier_of(info) -> string_view;
|
|
consteval auto display_string_of(info) -> string_view;
|
|
|
|
consteval auto u8identifier_of(info) -> u8string_view;
|
|
consteval auto u8display_string_of(info) -> u8string_view;
|
|
|
|
consteval auto has_identifier(info) -> bool;
|
|
|
|
enum operators;
|
|
|
|
consteval auto operator_of(info) -> operators;
|
|
|
|
consteval auto source_location_of(info r) -> source_location;
|
|
|
|
// type queries
|
|
consteval auto type_of(info) -> info;
|
|
consteval auto parent_of(info) -> info;
|
|
consteval auto dealias(info) -> info;
|
|
|
|
// object and value queries
|
|
consteval auto object_of(info) -> info;
|
|
consteval auto constant_of(info) -> info;
|
|
|
|
// template queries
|
|
consteval auto template_of(info r) -> info;
|
|
consteval auto template_arguments_of(info r) -> vector<info>;
|
|
|
|
// member queries
|
|
consteval auto members_of(info class_type, access_context ctx) -> vector<info>;
|
|
consteval auto bases_of(info class_type, access_context ctx) -> vector<info>;
|
|
consteval auto static_data_members_of(info class_type,
|
|
access_context ctx) -> vector<info>;
|
|
consteval auto nonstatic_data_members_of(info class_type,
|
|
access_context ctx) -> vector<info>;
|
|
consteval auto enumerators_of(info enum_type) -> vector<info>;
|
|
|
|
// substitute
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto can_substitute(info templ, R &&args) -> bool;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto substitute(info templ, R &&args) -> info;
|
|
|
|
// reflect expression results
|
|
template <typename T>
|
|
consteval auto reflect_constant(const T&) -> info;
|
|
template <typename T>
|
|
consteval auto reflect_object(T &) -> info;
|
|
template <typename T>
|
|
consteval auto reflect_function(T &) -> info;
|
|
|
|
// extract<T>
|
|
template <typename Ty>
|
|
consteval auto extract(info) -> T;
|
|
|
|
// other type predicates
|
|
consteval auto is_public(info) -> bool;
|
|
consteval auto is_protected(info) -> bool;
|
|
consteval auto is_private(info) -> bool;
|
|
consteval auto is_virtual(info) -> bool;
|
|
consteval auto is_pure_virtual(info) -> bool;
|
|
consteval auto is_override(info) -> bool;
|
|
consteval auto is_deleted(info) -> bool;
|
|
consteval auto is_defaulted(info) -> bool;
|
|
consteval auto is_explicit(info) -> bool;
|
|
consteval bool is_noexcept(info) -> bool;
|
|
consteval auto is_bit_field(info) -> bool;
|
|
consteval auto is_enumerator(info) -> bool;
|
|
consteval auto is_const(info) -> bool;
|
|
consteval auto is_volatile(info) -> bool;
|
|
consteval auto is_mutable_member(info) -> bool;
|
|
consteval auto is_lvalue_reference_qualified(info) -> bool;
|
|
consteval auto is_rvalue_reference_qualified(info) -> bool;
|
|
consteval auto has_static_storage_duration(info) -> bool;
|
|
consteval auto has_thread_storage_duration(info r) -> bool;
|
|
consteval auto has_automatic_storage_duration(info r) -> bool;
|
|
consteval auto has_internal_linkage(info) -> bool;
|
|
consteval auto has_module_linkage(info) -> bool;
|
|
consteval auto has_external_linkage(info) -> bool;
|
|
consteval auto has_linkage(info) -> bool;
|
|
consteval auto is_class_member(info) -> bool;
|
|
consteval auto is_namespace_member(info) -> bool;
|
|
consteval auto is_nonstatic_data_member(info) -> bool;
|
|
consteval auto is_static_member(info) -> bool;
|
|
consteval auto is_base(info) -> bool;
|
|
consteval auto is_data_member_spec(info) -> bool;
|
|
consteval auto is_namespace(info) -> bool;
|
|
consteval auto is_function(info) -> bool;
|
|
consteval auto is_variable(info) -> bool;
|
|
consteval auto is_type(info) -> bool;
|
|
consteval auto is_type_alias(info) -> bool;
|
|
consteval auto is_namespace_alias(info) -> bool;
|
|
consteval auto is_complete_type(info) -> bool;
|
|
consteval auto is_enumerable_type(info) -> bool;
|
|
consteval auto is_template(info) -> bool;
|
|
consteval auto is_function_template(info) -> bool;
|
|
consteval auto is_variable_template(info) -> bool;
|
|
consteval auto is_class_template(bool) -> bool;
|
|
consteval auto is_alias_template(bool) -> bool;
|
|
consteval auto is_conversion_function_template(bool) -> bool;
|
|
consteval auto is_operator_function_template(bool) -> bool;
|
|
consteval auto is_literal_operator_template(bool) -> bool;
|
|
consteval auto is_constructor_template(bool) -> bool;
|
|
consteval auto is_concept(info) -> bool;
|
|
consteval auto is_structured_binding(info) -> bool;
|
|
consteval auto has_template_arguments(info) -> bool;
|
|
consteval auto has_default_member_initializer(info) -> bool;
|
|
consteval auto is_conversion_function(info) -> bool;
|
|
consteval auto is_operator_function(info) -> bool;
|
|
consteval auto is_literal_operator(info) -> bool;
|
|
consteval auto is_constructor(info) -> bool;
|
|
consteval auto is_default_constructor(info) -> bool;
|
|
consteval auto is_copy_constructor(info) -> bool;
|
|
consteval auto is_move_constructor(info) -> bool;
|
|
consteval auto is_assignment(info) -> bool;
|
|
consteval auto is_copy_assignment(info) -> bool;
|
|
consteval auto is_move_assignment(info) -> bool;
|
|
consteval auto is_destructor(info) -> bool;
|
|
consteval auto is_special_member_function(info) -> bool;
|
|
consteval auto is_user_provided(info) -> bool;
|
|
consteval auto is_user_declared(info) -> bool;
|
|
|
|
// define_aggregate
|
|
struct data_member_options;
|
|
consteval auto data_member_spec(info class_type,
|
|
data_member_options = {}) -> info;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto define_aggregate(info class_type, R &&members) -> info;
|
|
|
|
// data layout
|
|
struct member_offset {
|
|
ptrdiff_t bytes;
|
|
ptrdiff_t bits;
|
|
|
|
constexpr size_t total_bits() const;
|
|
auto operator<=>(member_offset const&) const = default;
|
|
};
|
|
consteval auto offset_of(info) -> member_offset;
|
|
consteval auto size_of(info) -> size_t;
|
|
consteval auto alignment_of(info) -> size_t;
|
|
consteval auto bit_size_of(info) -> size_t;
|
|
|
|
// primary type categories
|
|
consteval auto is_void_type(info) -> bool;
|
|
consteval auto is_null_pointer_type(info) -> bool;
|
|
consteval auto is_integral_type(info) -> bool;
|
|
consteval auto is_floating_point_type(info) -> bool;
|
|
consteval auto is_array_type(info) -> bool;
|
|
consteval auto is_pointer_type(info) -> bool;
|
|
consteval auto is_lvalue_reference_type(info) -> bool;
|
|
consteval auto is_rvalue_reference_type(info) -> bool;
|
|
consteval auto is_member_object_pointer_type(info) -> bool;
|
|
consteval auto is_member_function_pointer_type(info) -> bool;
|
|
consteval auto is_enum_type(info) -> bool;
|
|
consteval auto is_union_type(info) -> bool;
|
|
consteval auto is_class_type(info) -> bool;
|
|
consteval auto is_function_type(info) -> bool;
|
|
consetval auto is_reflection_type(info) -> bool;
|
|
|
|
// composite type categories
|
|
consteval auto is_reference_type(info) -> bool;
|
|
consteval auto is_arithmetic_type(info) -> bool;
|
|
consteval auto is_fundamental_type(info) -> bool;
|
|
consteval auto is_object_type(info) -> bool;
|
|
consteval auto is_scalar_type(info) -> bool;
|
|
consteval auto is_compound_type(info) -> bool;
|
|
consteval auto is_member_pointer_type(info) -> bool;
|
|
|
|
// type properties
|
|
consteval auto is_const_type(info) -> bool;
|
|
consteval auto is_volatile_type(info) -> bool;
|
|
consteval auto is_trivial_type(info) -> bool;
|
|
consteval auto is_trivially_copyable_type(info) -> bool;
|
|
consteval auto is_standard_layout_type(info) -> bool;
|
|
consteval auto is_empty_type(info) -> bool;
|
|
consteval auto is_polymorphic_type(info) -> bool;
|
|
consteval auto is_abstract_type(info) -> bool;
|
|
consteval auto is_final_type(info) -> bool;
|
|
consteval auto is_aggregate_type(info) -> bool;
|
|
consteval auto is_consteval_only_type(info) -> bool;
|
|
consteval auto is_signed_type(info) -> bool;
|
|
consteval auto is_unsigned_type(info) -> bool;
|
|
consteval auto is_bounded_array_type(info) -> bool;
|
|
consteval auto is_unbounded_array_type(info) -> bool;
|
|
consteval auto is_scoped_enum_type(info) -> bool;
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_constructible_type(info, R &&args) -> bool;
|
|
consteval auto is_default_constructible_type(info) -> bool;
|
|
consteval auto is_copy_constructible_type(info) -> bool;
|
|
consteval auto is_move_constructible_type(info) -> bool;
|
|
|
|
consteval auto is_assignable_type(info dst, info src) -> bool;
|
|
consteval auto is_copy_assignable_type(info) -> bool;
|
|
consteval auto is_move_assignable_type(info) -> bool;
|
|
|
|
consteval auto is_swappable_with_type(info dst, info src) -> bool;
|
|
consteval auto is_swappable_type(info) -> bool;
|
|
|
|
consteval auto is_destructible_type(info) -> bool;
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto type_is_trivially_constructible(info, R &&args) -> bool;
|
|
consteval auto is_trivially_default_constructible_type(info) -> bool;
|
|
consteval auto is_trivially_copy_constructible_type(info) -> bool;
|
|
consteval auto is_trivially_move_constructible_type(info) -> bool;
|
|
|
|
consteval auto is_trivially_assignable_type(info dst, info src) -> bool;
|
|
consteval auto is_trivially_copy_assignable_type(info) -> bool;
|
|
consteval auto is_trivially_move_assignable_type(info) -> bool;
|
|
consteval auto is_trivially_destructible_type(info) -> bool;
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_nothrow_constructible_type(info, R &&args) -> bool;
|
|
consteval auto is_nothrow_default_constructible_type(info) -> bool;
|
|
consteval auto is_nothrow_copy_constructible_type(info) -> bool;
|
|
consteval auto is_nothrow_move_constructible_type(info) -> bool;
|
|
|
|
consteval auto is_nothrow_assignable_type(info dst, info src) -> bool;
|
|
consteval auto is_nothrow_copy_assignable_type(info) -> bool;
|
|
consteval auto is_nothrow_move_assignable_type(info) -> bool;
|
|
|
|
consteval auto is_nothrow_swappable_with_type(info dst, info src) -> bool;
|
|
consteval auto is_nothrow_swappable_type(info) -> bool;
|
|
|
|
consteval auto is_nothrow_destructible_type(info) -> bool;
|
|
|
|
consteval auto is_implicit_lifetime_type(info) -> bool;
|
|
|
|
consteval auto has_virtual_destructor(info) -> bool;
|
|
|
|
consteval auto has_unique_object_representations(info) -> bool;
|
|
|
|
consteval auto reference_constructs_from_temporary(info) -> bool;
|
|
consteval auto reference_converts_from_temporary(info) -> bool;
|
|
|
|
// type property queries
|
|
consteval auto rank(info) -> size_t;
|
|
consteval auto extent(info type, unsigned i) -> size_t;
|
|
|
|
// type relations
|
|
consteval auto is_same_type(info, info) -> bool;
|
|
consteval auto is_base_of_type(info, info) -> bool;
|
|
consteval auto is_convertible_type(info, info) -> bool;
|
|
consteval auto is_nothrow_convertible_type(info, info) -> bool;
|
|
consteval auto is_layout_compatible_type(info, info) -> bool;
|
|
consteval auto is_pointer_interconvertible_base_of_type(info, info) -> bool;
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_invocable_type(info type, R &&args) -> bool;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_invocable_r_type(info result, info type,
|
|
R &&args) -> bool;
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_nothrow_invocable_type(info type, R &&args) -> bool;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_nothrow_invocable_r_type(info result, info type,
|
|
R &&args) -> bool;
|
|
|
|
// const volatile modifications
|
|
consteval auto remove_const(info) -> info;
|
|
consteval auto remove_volatile(info) -> info;
|
|
consteval auto remove_cv(info) -> info;
|
|
consteval auto add_const(info) -> info;
|
|
consteval auto add_volatile(info) -> info;
|
|
consteval auto add_cv(info) -> info;
|
|
|
|
// reference modifications
|
|
consteval auto remove_reference(info) -> info;
|
|
consteval auto add_lvalue_reference(info) -> info;
|
|
consteval auto add_rvalue_reference(info) -> info;
|
|
|
|
// sign modifications
|
|
consteval auto make_signed(info) -> info;
|
|
consteval auto make_unsigned(info) -> info;
|
|
|
|
// array modifications
|
|
consteval auto remove_extent(info) -> info;
|
|
consteval auto remove_all_extents(info) -> info;
|
|
|
|
// pointer modifications
|
|
consteval auto remove_pointer(info) -> info;
|
|
consteval auto add_pointer(info) -> info;
|
|
|
|
// other transformations
|
|
consteval auto remove_cvref(info) -> info;
|
|
consteval auto decay(info) -> info;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto common_type(R &&args) -> info;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto common_reference(R &&args) -> info;
|
|
consteval auto underlying_type(info) -> info;
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto invoke_result(info type, R &&args) -> info;
|
|
consteval auto unwrap_reference(info) -> info;
|
|
consteval auto unwrap_ref_decay(info) -> info;
|
|
|
|
// tuple and variant queries
|
|
consteval auto tuple_size(info) -> size_t;
|
|
consteval auto tuple_element(size_t, info) -> info;
|
|
|
|
consteval auto variant_size(info) -> size_t;
|
|
consteval auto variant_alternative(size_t, info) -> info;
|
|
|
|
// entity proxies (PXYZ)
|
|
consteval auto is_entity_proxy(info) -> bool;
|
|
|
|
// function parameters (P3096)
|
|
consteval auto parameters_of(info) -> vector<info>;
|
|
consteval auto has_ellipsis_parameter(info) -> bool;
|
|
consteval auto has_default_argument(info) -> bool;
|
|
consteval auto is_explicit_object_parameter(info) -> bool;
|
|
consteval auto is_function_parameter(info) -> bool;
|
|
consteval auto return_type_of(info) -> info;
|
|
consteval auto variable_of(info) -> info;
|
|
|
|
// annotations (P3394)
|
|
consteval auto annotations_of(info) -> vector<info>;
|
|
consteval auto annotations_of(info, info) -> vector<info>;
|
|
template <typename T>
|
|
consteval auto annotation_of_type(info) -> optional<info>;
|
|
consteval auto is_annotation(info) -> bool;
|
|
consteval auto annotate(info) -> info;
|
|
|
|
// modeling access control (P3547)
|
|
struct access_context {
|
|
access_context() = delete;
|
|
|
|
consteval auto scope() const -> info;
|
|
consteval auto designating_class() const -> info;
|
|
|
|
static consteval auto current() noexcept -> access_context;
|
|
static consteval auto unprivileged() noexcept -> access_context;
|
|
static consteval auto unchecked() noexcept -> access_context;
|
|
|
|
consteval auto via(info) const -> access_context;
|
|
};
|
|
|
|
consteval auto is_accessible(info r, access_context ctx) -> bool;
|
|
consteval auto has_inaccessible_nonstatic_data_members(
|
|
info r,
|
|
access_context cls) -> vector<info>;
|
|
consteval auto has_inaccessible_bases(
|
|
info r,
|
|
access_context cls) -> vector<info>;
|
|
|
|
// other bespoke functions (not proposed at this time)
|
|
consteval auto is_access_specified(info) -> bool;
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto reflect_invoke(info target, R &&args) -> info;
|
|
template <reflection_range R1 = initializer_list<info>,
|
|
reflection_range R2 = initializer_list<info>>
|
|
consteval auto reflect_invoke(info target,
|
|
R1 &&tmpl_args, R2 &&args) -> info;
|
|
|
|
|
|
} // namespace reflection_v2
|
|
} // namespace meta
|
|
} // namespace std
|
|
|
|
*/
|
|
|
|
#include <__config>
|
|
#include <algorithm>
|
|
#include <bit>
|
|
#include <initializer_list>
|
|
#include <optional>
|
|
#include <ranges>
|
|
#include <source_location>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <type_traits>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#if __has_feature(reflection)
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2
|
|
|
|
// An opaque handle to a reflected entity.
|
|
using info = decltype(^^int);
|
|
|
|
template <typename R>
|
|
concept reflection_range =
|
|
ranges::input_range<R> &&
|
|
same_as<ranges::range_value_t<R>, info> &&
|
|
same_as<remove_cvref_t<ranges::range_reference_t<R>>, info>;
|
|
|
|
namespace detail {
|
|
enum : unsigned {
|
|
|
|
// non-exposed metafunctions
|
|
__metafn_get_begin_enumerator_decl_of,
|
|
__metafn_get_get_next_enumerator_decl_of,
|
|
__metafn_get_ith_base_of,
|
|
__metafn_get_ith_template_argument_of,
|
|
__metafn_get_begin_member_decl_of,
|
|
__metafn_get_next_member_decl_of,
|
|
__metafn_is_structural_type,
|
|
__metafn_map_decl_to_entity,
|
|
|
|
// P2996 metafunctions
|
|
__metafn_identifier_of,
|
|
__metafn_has_identifier,
|
|
__metafn_operator_of,
|
|
__metafn_source_location_of,
|
|
__metafn_type_of,
|
|
__metafn_parent_of,
|
|
__metafn_underlying_entity_of,
|
|
__metafn_proxied_entity_of,
|
|
__metafn_object_of,
|
|
__metafn_constant_of,
|
|
__metafn_template_of,
|
|
__metafn_substitute,
|
|
__metafn_extract,
|
|
__metafn_is_public,
|
|
__metafn_is_protected,
|
|
__metafn_is_private,
|
|
__metafn_is_virtual,
|
|
__metafn_is_pure_virtual,
|
|
__metafn_is_override,
|
|
__metafn_is_deleted,
|
|
__metafn_is_defaulted,
|
|
__metafn_is_explicit,
|
|
__metafn_is_noexcept,
|
|
__metafn_is_bit_field,
|
|
__metafn_is_enumerator,
|
|
__metafn_is_const,
|
|
__metafn_is_volatile,
|
|
__metafn_is_mutable_member,
|
|
__metafn_is_lvalue_reference_qualified,
|
|
__metafn_is_rvalue_reference_qualified,
|
|
__metafn_has_static_storage_duration,
|
|
__metafn_has_thread_storage_duration,
|
|
__metafn_has_automatic_storage_duration,
|
|
__metafn_has_internal_linkage,
|
|
__metafn_has_module_linkage,
|
|
__metafn_has_external_linkage,
|
|
__metafn_has_linkage,
|
|
__metafn_is_class_member,
|
|
__metafn_is_namespace_member,
|
|
__metafn_is_nonstatic_data_member,
|
|
__metafn_is_static_member,
|
|
__metafn_is_base,
|
|
__metafn_is_data_member_spec,
|
|
__metafn_is_namespace,
|
|
__metafn_is_function,
|
|
__metafn_is_variable,
|
|
__metafn_is_type,
|
|
__metafn_is_alias,
|
|
__metafn_is_entity_proxy,
|
|
__metafn_is_complete_type,
|
|
__metafn_has_complete_definition,
|
|
__metafn_is_enumerable_type,
|
|
__metafn_is_template,
|
|
__metafn_is_function_template,
|
|
__metafn_is_variable_template,
|
|
__metafn_is_class_template,
|
|
__metafn_is_alias_template,
|
|
__metafn_is_conversion_function_template,
|
|
__metafn_is_operator_function_template,
|
|
__metafn_is_literal_operator_template,
|
|
__metafn_is_constructor_template,
|
|
__metafn_is_concept,
|
|
__metafn_is_structured_binding,
|
|
__metafn_is_value,
|
|
__metafn_is_object,
|
|
__metafn_has_template_arguments,
|
|
__metafn_has_default_member_initializer,
|
|
__metafn_is_conversion_function,
|
|
__metafn_is_operator_function,
|
|
__metafn_is_literal_operator,
|
|
__metafn_is_constructor,
|
|
__metafn_is_default_constructor,
|
|
__metafn_is_copy_constructor,
|
|
__metafn_is_move_constructor,
|
|
__metafn_is_assignment,
|
|
__metafn_is_copy_assignment,
|
|
__metafn_is_move_assignment,
|
|
__metafn_is_destructor,
|
|
__metafn_is_special_member_function,
|
|
__metafn_is_user_provided,
|
|
__metafn_is_user_declared,
|
|
__metafn_reflect_result,
|
|
__metafn_data_member_spec,
|
|
__metafn_define_aggregate,
|
|
__metafn_offset_of,
|
|
__metafn_size_of,
|
|
__metafn_bit_offset_of,
|
|
__metafn_bit_size_of,
|
|
__metafn_alignment_of,
|
|
|
|
// P3096 parameter reflection metafunctions
|
|
__metafn_get_ith_parameter_of,
|
|
__metafn_has_ellipsis_parameter,
|
|
__metafn_has_default_argument,
|
|
__metafn_is_explicit_object_parameter,
|
|
__metafn_is_function_parameter,
|
|
__metafn_return_type_of,
|
|
__metafn_variable_of,
|
|
|
|
// P3394 annotation metafunctions
|
|
__metafn_get_ith_annotation_of,
|
|
__metafn_is_annotation,
|
|
__metafn_annotate,
|
|
|
|
// P3493 accessibility metafunctions
|
|
__metafn_access_context,
|
|
__metafn_is_accessible,
|
|
|
|
// Other bespoke functions (not proposed at this time)
|
|
__metafn_is_access_specified,
|
|
__metafn_reflect_invoke,
|
|
};
|
|
|
|
consteval auto __workaround_expand_compiler_builtins(info type) -> info;
|
|
|
|
consteval auto __underlying_entity_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_underlying_entity_of, r);
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
namespace __range_of_infos {
|
|
|
|
struct sentinel {};
|
|
|
|
template <typename Front, typename Next, typename Map>
|
|
class iterator {
|
|
static constexpr Front m_front = { };
|
|
static constexpr Next m_next = { };
|
|
|
|
// The reflected entity passed to the underlying range
|
|
info m_reflectedEntity{^^sentinel};
|
|
// The current meta::info within the range: e.g. if we are
|
|
// doing template_arguments_of(^^vector<int, double, string>)
|
|
// m_currInfoItr can be either ^^int, ^^double and ^^string
|
|
info m_currInfoItr{^^sentinel};
|
|
|
|
Map m_mapFn;
|
|
size_t m_nextIndex {0};
|
|
|
|
public:
|
|
using value_type = info;
|
|
using reference = info;
|
|
using pointer = info;
|
|
using difference_type = ptrdiff_t;
|
|
using iterator_category = forward_iterator_tag;
|
|
|
|
consteval iterator()
|
|
: m_currInfoItr{^^sentinel}
|
|
, m_mapFn{}
|
|
{ }
|
|
|
|
consteval iterator(meta::info reflectedEntity)
|
|
: m_reflectedEntity{reflectedEntity}
|
|
, m_currInfoItr{m_front(reflectedEntity)}
|
|
, m_nextIndex{1} // after we fetch the front, next index is 1
|
|
{ }
|
|
|
|
consteval info operator*() const {
|
|
return m_mapFn(m_currInfoItr);
|
|
}
|
|
|
|
// pre-incr ++itr;
|
|
consteval iterator operator++() {
|
|
m_currInfoItr = m_next(m_currInfoItr, m_reflectedEntity, m_nextIndex++);
|
|
return *this;
|
|
}
|
|
|
|
// post-incr itr++;
|
|
consteval iterator operator++(int) {
|
|
iterator tmp = *this;
|
|
operator++();
|
|
return tmp;
|
|
}
|
|
|
|
consteval friend bool operator==(iterator a, iterator b) {
|
|
return a.m_currInfoItr == b.m_currInfoItr;
|
|
}
|
|
|
|
consteval friend bool operator!=(iterator a, iterator b) {
|
|
return a.m_currInfoItr != b.m_currInfoItr;
|
|
}
|
|
};
|
|
|
|
template <typename Iter>
|
|
class range {
|
|
Iter m_first;
|
|
Iter m_last;
|
|
|
|
public:
|
|
using iterator = Iter;
|
|
|
|
consteval range(info reflection)
|
|
: m_first(reflection), m_last()
|
|
{ }
|
|
|
|
consteval iterator begin() const
|
|
{
|
|
return m_first;
|
|
}
|
|
|
|
consteval iterator end() const
|
|
{
|
|
return m_last;
|
|
}
|
|
};
|
|
|
|
template <typename Front, typename Next, typename Map>
|
|
consteval ptrdiff_t distance(iterator<Front, Next, Map> first,
|
|
iterator<Front, Next, Map> last) {
|
|
ptrdiff_t n = 0;
|
|
for (; first != last; ++first)
|
|
++n;
|
|
return n;
|
|
}
|
|
|
|
constexpr struct next_member_of_fn {
|
|
consteval info operator()(info currItrInfo, auto /* reflectedEntity */,
|
|
auto /* idx */) const {
|
|
return __metafunction(detail::__metafn_get_next_member_decl_of, currItrInfo,
|
|
^^sentinel);
|
|
}
|
|
} next_member;
|
|
|
|
constexpr struct front_member_of_fn {
|
|
consteval info operator()(info reflectedEntity) const {
|
|
return __metafunction(detail::__metafn_get_begin_member_decl_of,
|
|
reflectedEntity, ^^sentinel);
|
|
}
|
|
} front_member;
|
|
|
|
constexpr struct map_decl_to_entity_fn {
|
|
consteval info operator()(info reflectedDecl) const {
|
|
return __metafunction(detail::__metafn_map_decl_to_entity, reflectedDecl);
|
|
}
|
|
} map_decl_to_entity;
|
|
|
|
constexpr struct map_identity_fn {
|
|
consteval info operator()(info reflectedDecl) const {
|
|
return reflectedDecl;
|
|
}
|
|
} map_identity;
|
|
|
|
constexpr struct next_targ_fn {
|
|
consteval info operator()(auto /* currItrInfo */, info reflectedEntity,
|
|
size_t idx) const {
|
|
return __metafunction(detail::__metafn_get_ith_template_argument_of,
|
|
reflectedEntity, ^^sentinel, idx);
|
|
}
|
|
} next_targ;
|
|
|
|
constexpr struct front_targ_fn {
|
|
consteval info operator()(info reflectedEntity) const {
|
|
return __metafunction(detail::__metafn_get_ith_template_argument_of,
|
|
reflectedEntity, ^^sentinel, 0);
|
|
}
|
|
} front_targ;
|
|
|
|
constexpr struct next_base_of_fn {
|
|
consteval info operator()(auto /* currItrInfo */, info reflectedEntity,
|
|
size_t idx) const {
|
|
return __metafunction(detail::__metafn_get_ith_base_of,
|
|
reflectedEntity, ^^sentinel, idx);
|
|
}
|
|
} next_base;
|
|
|
|
constexpr struct front_base_of_fn {
|
|
consteval info operator()(info reflectedEntity) const {
|
|
return __metafunction(detail::__metafn_get_ith_base_of,
|
|
reflectedEntity, ^^sentinel, 0);
|
|
}
|
|
} front_base;
|
|
|
|
constexpr struct next_enumerator_of_fn {
|
|
consteval info operator()(info currItrInfo, auto /* reflectedEntity */,
|
|
auto /* idx */ ) const {
|
|
|
|
return __metafunction(detail::__metafn_get_get_next_enumerator_decl_of,
|
|
currItrInfo, ^^sentinel);
|
|
}
|
|
} next_enumerator;
|
|
|
|
constexpr struct front_enumerator_of_fn {
|
|
consteval info operator()(info reflectedEntity) const {
|
|
return __metafunction(detail::__metafn_get_begin_enumerator_decl_of,
|
|
reflectedEntity, ^^sentinel);
|
|
}
|
|
} front_enumerator;
|
|
|
|
#if __has_feature(parameter_reflection)
|
|
|
|
struct next_parameter_of_fn {
|
|
consteval info operator()(auto /* currItrInfo */, info reflectedEntity,
|
|
size_t idx) const {
|
|
return __metafunction(detail::__metafn_get_ith_parameter_of,
|
|
reflectedEntity, ^^sentinel, idx);
|
|
}
|
|
};
|
|
|
|
struct front_parameter_of_fn {
|
|
consteval info operator()(info reflectedEntity) const {
|
|
return __metafunction(detail::__metafn_get_ith_parameter_of,
|
|
reflectedEntity, ^^sentinel, 0);
|
|
}
|
|
};
|
|
|
|
#endif // __has_feature(parameter_reflection)
|
|
|
|
// TODO(P2996): Guard on feature flag.
|
|
|
|
struct next_annotation_of {
|
|
consteval info operator()(auto /*currItrInfo */, info reflectedEntity,
|
|
size_t idx) const {
|
|
return __metafunction(detail::__metafn_get_ith_annotation_of,
|
|
reflectedEntity, ^^sentinel, idx);
|
|
}
|
|
};
|
|
|
|
struct front_annotation_of {
|
|
consteval info operator()(info reflectedEntity) const {
|
|
return __metafunction(detail::__metafn_get_ith_annotation_of,
|
|
reflectedEntity, ^^sentinel, 0);
|
|
}
|
|
};
|
|
|
|
} // namespace __range_of_infos
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Metafunctions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Returns a reflection of the canonical type for the reflected type.
|
|
#if __has_feature(entity_proxy_reflection)
|
|
[[deprecated("renamed to 'underlying_entity_of' in PXYZ")]]
|
|
#endif
|
|
consteval auto dealias(info r) -> info {
|
|
return __metafunction(detail::__metafn_underlying_entity_of, r);
|
|
}
|
|
|
|
#if __has_feature(entity_proxy_reflection)
|
|
consteval auto underlying_entity_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_underlying_entity_of, r);
|
|
}
|
|
|
|
consteval auto proxied_entity_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_proxied_entity_of, r);
|
|
}
|
|
#endif
|
|
|
|
// Returns the identifier for the represented entity. If the entity is a
|
|
// literal operator or literal operator template, then this is the identifier
|
|
// suffix for the literal operator.
|
|
consteval auto identifier_of(info r) -> string_view {
|
|
return __metafunction(detail::__metafn_identifier_of, ^^const char *, r,
|
|
/*UTF8=*/false, /*EnforceConsistent=*/true);
|
|
}
|
|
|
|
consteval auto u8identifier_of(info r) -> u8string_view {
|
|
return __metafunction(detail::__metafn_identifier_of, ^^const char8_t *,
|
|
r, /*UTF8=*/true, /*EnforceConsistent=*/true);
|
|
}
|
|
|
|
// Returns an implementation-defined name for the reflected entity.
|
|
consteval auto display_string_of(info r) -> string_view;
|
|
consteval auto u8display_string_of(info r) -> u8string_view;
|
|
|
|
// Enumeration of all overloadable operators.
|
|
enum class operators {
|
|
op_new = 1, op_delete, op_array_new, op_array_delete, op_co_await,
|
|
op_parentheses, op_square_brackets, op_arrow, op_arrow_star, op_tilde,
|
|
op_exclamation, op_plus, op_minus, op_star, op_slash, op_percent, op_caret,
|
|
op_ampersand, op_pipe, op_equals, op_plus_equals, op_minus_equals,
|
|
op_star_equals, op_slash_equals, op_percent_equals, op_caret_equals,
|
|
op_ampersand_equals, op_pipe_equals, op_equals_equals, op_exclamation_equals,
|
|
op_less, op_greater, op_less_equals, op_greater_equals, op_spaceship,
|
|
op_ampersand_ampersand, op_pipe_pipe, op_less_less, op_greater_greater,
|
|
op_less_less_equals, op_greater_greater_equals, op_plus_plus, op_minus_minus,
|
|
op_comma,
|
|
};
|
|
using enum operators;
|
|
|
|
// Returns the operator overloaded by the represented operator function or
|
|
// operator function template.
|
|
consteval auto operator_of(info r) -> operators {
|
|
return operators(__metafunction(detail::__metafn_operator_of, r));
|
|
}
|
|
|
|
// Returns whether the reflected entity has an associated identifier.
|
|
consteval auto has_identifier(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_identifier, r);
|
|
}
|
|
|
|
// Returns the string representation of the operator.
|
|
consteval auto symbol_of(operators op) -> string_view {
|
|
static constexpr string_view op_names[45] = {
|
|
{}, "new", "delete", "new[]", "delete[]", "coawait", "()", "[]", "->",
|
|
"->*", "~", "!", "+", "-", "*", "/", "%", "^", "&", "|", "=", "+=", "-=",
|
|
"*=", "/=", "%=", "^", "&=", "|=", "==", "!=", "<", ">", "<=", ">=",
|
|
"<=>", "&&", "||", "<<", ">>", "<<=", ">>=", "++", "--", ","
|
|
};
|
|
return op_names[int(op)];
|
|
}
|
|
|
|
consteval auto u8symbol_of(operators op) -> u8string_view {
|
|
static constexpr u8string_view op_names[45] = {
|
|
{}, u8"new", u8"delete", u8"new[]", u8"delete[]", u8"coawait", u8"()",
|
|
u8"[]", u8"->", u8"->*", u8"~", u8"!", u8"+", u8"-", u8"*", u8"/", u8"%",
|
|
u8"^", u8"&", u8"|", u8"=", u8"+=", u8"-=", u8"*=", u8"/=", u8"%=",
|
|
u8"^", u8"&=", u8"|=", u8"==", u8"!=", u8"<", u8">", u8"<=", u8">=",
|
|
u8"<=>", u8"&&", u8"||", u8"<<", u8">>", u8"<<=", u8">>=", u8"++",
|
|
u8"--", u8","
|
|
};
|
|
return op_names[int(op)];
|
|
}
|
|
|
|
// Returns the source location of the reflected entity.
|
|
consteval auto source_location_of(info r) -> source_location {
|
|
auto ptr = __metafunction(detail::__metafn_source_location_of, r);
|
|
return source_location::current(ptr);
|
|
}
|
|
|
|
// Returns the type of the provided reflection of an expression.
|
|
consteval auto type_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_type_of, r);
|
|
}
|
|
|
|
// Returns the containing class or namespace of a class or namespace member.
|
|
consteval auto parent_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_parent_of, r);
|
|
}
|
|
|
|
// Returns a reflection of the object designated by the reflected entity.
|
|
consteval auto object_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_object_of, r);
|
|
}
|
|
|
|
// Returns a reflection of the value evaluated from the reflected entity.
|
|
consteval auto constant_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_constant_of, r);
|
|
}
|
|
|
|
// Returns a reflection of the template from which the reflected entity was
|
|
// instantiated.
|
|
consteval auto template_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_template_of, r);
|
|
}
|
|
|
|
consteval auto template_arguments_of(info r) -> vector<info> {
|
|
using iterator =
|
|
__range_of_infos::iterator<__range_of_infos::front_targ_fn,
|
|
__range_of_infos::next_targ_fn,
|
|
__range_of_infos::map_identity_fn>;
|
|
using range = __range_of_infos::range<iterator>;
|
|
auto rng = range{r};
|
|
return vector<info>{rng.begin(), rng.end()};
|
|
}
|
|
|
|
// Returns whether the reflected entity is a member of a class.
|
|
consteval auto is_class_member(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_class_member, r);
|
|
}
|
|
|
|
|
|
// Returns whether the reflected entity is a non-static data member.
|
|
consteval auto is_nonstatic_data_member(info r) -> bool {
|
|
return is_class_member(r) &&
|
|
__metafunction(detail::__metafn_is_nonstatic_data_member, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a static member.
|
|
consteval auto is_static_member(info r) -> bool {
|
|
return is_class_member(r) &&
|
|
__metafunction(detail::__metafn_is_static_member, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a base class specifier.
|
|
consteval auto is_base(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_base, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a description of a data member.
|
|
consteval auto is_data_member_spec(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_data_member_spec, r);
|
|
}
|
|
|
|
// Returns whether 'templ' substituted with 'args' forms a valid template-id.
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto can_substitute(info templ, R &&args) -> bool {
|
|
info sub;
|
|
if constexpr (ranges::contiguous_range<R>) {
|
|
sub = __metafunction(detail::__metafn_substitute, templ,
|
|
ranges::data(args), ranges::size(args), false);
|
|
} else {
|
|
vector vargs = args | ranges::to<vector>();
|
|
sub = __metafunction(detail::__metafn_substitute, templ,
|
|
vargs.data(), vargs.size(), false);
|
|
}
|
|
return sub != info{};
|
|
}
|
|
|
|
// Returns a reflection representing the template instantiation of the entity
|
|
// reflected by 'templ' with the entities reflected by 'args'.
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto substitute(info templ, R &&args) -> info {
|
|
if constexpr (ranges::contiguous_range<R>) {
|
|
return __metafunction(detail::__metafn_substitute, templ,
|
|
ranges::data(args), ranges::size(args), true);
|
|
} else {
|
|
vector vargs = args | ranges::to<vector>();
|
|
return __metafunction(detail::__metafn_substitute, templ, vargs.data(),
|
|
vargs.size(), true);
|
|
}
|
|
}
|
|
|
|
// Returns the value or object from 'r' if 'r' is a reflection of a value
|
|
// or object having type 'T'.
|
|
template <typename Ty> requires (!is_rvalue_reference_v<Ty>)
|
|
consteval auto extract(info r) -> Ty {
|
|
return __metafunction(detail::__metafn_extract, ^^Ty, r);
|
|
}
|
|
|
|
consteval auto is_class_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_class_v, {r}));
|
|
}
|
|
|
|
// Returns true if the reflected entity is a complete type.
|
|
consteval auto is_complete_type(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_complete_type, r);
|
|
}
|
|
|
|
// Returns whether the reflected class data member is an enumerator.
|
|
consteval auto is_enumerator(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_enumerator, r);
|
|
}
|
|
|
|
class access_context {
|
|
consteval access_context(info scope, info designating_class) noexcept
|
|
: d_scope{scope}, d_designating_class{designating_class} { }
|
|
|
|
public:
|
|
const info d_scope;
|
|
const info d_designating_class;
|
|
|
|
consteval access_context() = delete;
|
|
|
|
consteval access_context(const access_context &) noexcept = default;
|
|
consteval access_context(access_context &&) noexcept = default;
|
|
|
|
consteval info scope() const { return d_scope; }
|
|
consteval info designating_class() const { return d_designating_class; }
|
|
|
|
[[clang::instantiation_dependent]]
|
|
static consteval access_context current() noexcept {
|
|
return {__metafunction(detail::__metafn_access_context), {}};
|
|
}
|
|
|
|
static consteval access_context unprivileged() noexcept {
|
|
return access_context{^^::, info{}};
|
|
}
|
|
|
|
static consteval access_context unchecked() noexcept {
|
|
return access_context{info{}, info{}};
|
|
}
|
|
|
|
consteval access_context via(info new_designating_class) const {
|
|
if (!is_class_type(new_designating_class))
|
|
throw "designating class must be a reflection of a class type";
|
|
|
|
return access_context{d_scope, new_designating_class};
|
|
}
|
|
};
|
|
|
|
consteval auto is_accessible(info r, access_context ctx) -> bool {
|
|
// Note: The accessibility of an enumerator may be looked up in a class
|
|
// for which it's not a member, since that enumerator could be
|
|
if (!is_class_member(r) && !is_base(r) && !is_enumerator(r))
|
|
return true;
|
|
|
|
return __metafunction(detail::__metafn_is_accessible,
|
|
r, ctx.scope(), ctx.designating_class());
|
|
}
|
|
|
|
consteval auto members_of(info r, access_context ctx) -> vector<info> {
|
|
using iterator =
|
|
__range_of_infos::iterator<__range_of_infos::front_member_of_fn,
|
|
__range_of_infos::next_member_of_fn,
|
|
__range_of_infos::map_decl_to_entity_fn>;
|
|
using range = __range_of_infos::range<iterator>;
|
|
auto rng = range{r};
|
|
|
|
vector<info> v {rng.begin(), rng.end()};
|
|
return vector<info>{
|
|
from_range,
|
|
v | views::filter([=](info r) { return is_accessible(r, ctx); })
|
|
};
|
|
}
|
|
|
|
// Returns whether the reflected entity is a namespace.
|
|
consteval auto is_namespace(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_namespace, r);
|
|
}
|
|
|
|
consteval auto bases_of(info r, access_context ctx) -> vector<info> {
|
|
if (is_namespace(r))
|
|
throw "Namespaces cannot have base classes";
|
|
|
|
using iterator =
|
|
__range_of_infos::iterator<__range_of_infos::front_base_of_fn,
|
|
__range_of_infos::next_base_of_fn,
|
|
__range_of_infos::map_identity_fn>;
|
|
using range = __range_of_infos::range<iterator>;
|
|
auto rng = range{r};
|
|
|
|
vector<info> v {rng.begin(), rng.end()};
|
|
return vector<info>{
|
|
from_range,
|
|
v | views::filter([=](info r) { return is_accessible(r, ctx); })
|
|
};
|
|
}
|
|
|
|
// Returns whether the reflected entity is a variable.
|
|
consteval auto is_variable(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_variable, r);
|
|
}
|
|
|
|
consteval auto static_data_members_of(info r,
|
|
access_context ctx) -> vector<info> {
|
|
if (is_namespace(r))
|
|
throw "Namespaces cannot have static data members";
|
|
|
|
return members_of(r, ctx) |
|
|
views::filter(is_variable) |
|
|
ranges::to<vector>();
|
|
}
|
|
|
|
consteval auto nonstatic_data_members_of(info r,
|
|
access_context ctx) -> vector<info> {
|
|
if (is_namespace(r))
|
|
throw "Namespaces cannot have non-static data members";
|
|
|
|
return members_of(r, ctx) |
|
|
views::filter(is_nonstatic_data_member) |
|
|
ranges::to<vector>();
|
|
}
|
|
|
|
// Returns true if the reflected entity is an enumerable type.
|
|
consteval auto is_enumerable_type(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_enumerable_type, r);
|
|
}
|
|
|
|
consteval auto enumerators_of(info r) -> vector<info> {
|
|
if (!is_enumerable_type(r))
|
|
throw "Reflection must represent an enumeration with a definition";
|
|
|
|
using iterator =
|
|
__range_of_infos::iterator<__range_of_infos::front_enumerator_of_fn,
|
|
__range_of_infos::next_enumerator_of_fn,
|
|
__range_of_infos::map_identity_fn>;
|
|
using range = __range_of_infos::range<iterator>;
|
|
auto rng = range{r};
|
|
return vector<info>{rng.begin(), rng.end()};
|
|
}
|
|
|
|
// Returns whether the reflected entity is a public class member.
|
|
consteval auto is_public(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_public, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a protected class member.
|
|
consteval auto is_protected(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_protected, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a private class member.
|
|
consteval auto is_private(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_private, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a virtual member function or a
|
|
// virtual base class.
|
|
consteval auto is_virtual(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_virtual, r);
|
|
}
|
|
|
|
// Returns whether the reflected class member function is pure virtual.
|
|
consteval auto is_pure_virtual(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_pure_virtual, r);
|
|
}
|
|
|
|
// Returns whether the reflected class member function overrides a virtual
|
|
// member function from a base class.
|
|
consteval auto is_override(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_override, r);
|
|
}
|
|
|
|
// Returns whether the reflected class member function is deleted.
|
|
consteval auto is_deleted(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_deleted, r);
|
|
}
|
|
|
|
// Returns whether the reflected class member function is defaulted.
|
|
consteval auto is_defaulted(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_defaulted, r);
|
|
}
|
|
|
|
// Returns whether the reflected class member function is explicit.
|
|
consteval auto is_explicit(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_explicit, r);
|
|
}
|
|
|
|
// Returns whether the reflected function type, function or member function
|
|
// is noexcept.
|
|
consteval auto is_noexcept(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_noexcept, r);
|
|
}
|
|
|
|
// Returns whether the reflected class data member is a bit field.
|
|
consteval auto is_bit_field(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_bit_field, r);
|
|
}
|
|
|
|
// Returns whether the reflected type is const-qualified, or if the reflected
|
|
// entity is of such a type.
|
|
consteval auto is_const(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_const, r);
|
|
}
|
|
|
|
// Returns whether the reflected type is volatile-qualified, or if the reflected
|
|
// entity is of such a type.
|
|
consteval auto is_volatile(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_volatile, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a mutable class member.
|
|
consteval auto is_mutable_member(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_mutable_member, r);
|
|
}
|
|
|
|
// Returns whether the reflected member function or function type is
|
|
// lvalue-reference qualified.
|
|
consteval auto is_lvalue_reference_qualified(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_lvalue_reference_qualified, r);
|
|
}
|
|
|
|
// Returns whether the reflected member function or function type is
|
|
// rvalue-reference qualified.
|
|
consteval auto is_rvalue_reference_qualified(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_rvalue_reference_qualified, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a variable having static storage
|
|
// duration.
|
|
consteval auto has_static_storage_duration(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_static_storage_duration, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a variable having thread storage
|
|
// duration.
|
|
consteval auto has_thread_storage_duration(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_thread_storage_duration, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a variable having automatic storage
|
|
// duration.
|
|
consteval auto has_automatic_storage_duration(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_automatic_storage_duration, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity has internal linkage.
|
|
consteval auto has_internal_linkage(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_internal_linkage, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity has module linkage.
|
|
consteval auto has_module_linkage(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_module_linkage, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity has external linkage.
|
|
consteval auto has_external_linkage(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_external_linkage, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity has linkage.
|
|
consteval auto has_linkage(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_linkage, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a member of a namespace.
|
|
consteval auto is_namespace_member(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_namespace_member, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a function.
|
|
consteval auto is_function(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_function, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a type.
|
|
consteval auto is_type(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_type, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a type alias.
|
|
consteval auto is_type_alias(info r) -> bool {
|
|
return is_type(r) && __metafunction(detail::__metafn_is_alias, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a namespace alias.
|
|
consteval auto is_namespace_alias(info r) -> bool {
|
|
return is_namespace(r) && __metafunction(detail::__metafn_is_alias, r);
|
|
}
|
|
|
|
#if __has_feature(entity_proxy_reflection)
|
|
// Returns true if the reflected entity is an entity proxy.
|
|
consteval auto is_entity_proxy(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_entity_proxy, r);
|
|
}
|
|
#endif
|
|
|
|
// Returns true if the reflected entity is a template.
|
|
consteval auto is_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_template, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a function template.
|
|
consteval auto is_function_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_function_template, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a variable template.
|
|
consteval auto is_variable_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_variable_template, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a class template.
|
|
consteval auto is_class_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_class_template, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is an alias template.
|
|
consteval auto is_alias_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_alias_template, r);
|
|
}
|
|
|
|
// Returns true if 'r' represents a conversion function template.
|
|
consteval auto is_conversion_function_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_conversion_function_template, r);
|
|
}
|
|
|
|
// Returns true if 'r' represents an operator function template.
|
|
consteval auto is_operator_function_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_operator_function_template, r);
|
|
}
|
|
|
|
// Returns true if 'r' represents a literal operator template.
|
|
consteval auto is_literal_operator_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_literal_operator_template, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a constructor template.
|
|
consteval auto is_constructor_template(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_constructor_template, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a concept.
|
|
consteval auto is_concept(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_concept, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a structured binding.
|
|
consteval auto is_structured_binding(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_structured_binding, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is a value.
|
|
consteval auto is_value(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_value, r);
|
|
}
|
|
|
|
// Returns true if the reflected entity is an object.
|
|
consteval auto is_object(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_object, r);
|
|
}
|
|
|
|
// Returns if the reflected entity has template arguments
|
|
consteval auto has_template_arguments(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_template_arguments, r);
|
|
}
|
|
|
|
// Returns if the reflected non-static data member has a default initializer.
|
|
consteval auto has_default_member_initializer(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_default_member_initializer, r);
|
|
}
|
|
|
|
// Returns whether 'r' represents a conversion function.
|
|
consteval auto is_conversion_function(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_conversion_function, r);
|
|
}
|
|
|
|
// Returns whether 'r' represents an operator function.
|
|
consteval auto is_operator_function(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_operator_function, r);
|
|
}
|
|
|
|
// Returns whether 'r' represents a literal operator.
|
|
consteval auto is_literal_operator(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_literal_operator, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a constructor.
|
|
consteval auto is_constructor(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_constructor, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a default constructor.
|
|
consteval auto is_default_constructor(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_default_constructor, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a copy constructor.
|
|
consteval auto is_copy_constructor(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_copy_constructor, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a move constructor.
|
|
consteval auto is_move_constructor(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_move_constructor, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is an assignment operator.
|
|
consteval auto is_assignment(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_assignment, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a copy assignment operator.
|
|
consteval auto is_copy_assignment(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_copy_assignment, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a move assignment operator.
|
|
consteval auto is_move_assignment(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_move_assignment, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a destructor.
|
|
consteval auto is_destructor(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_destructor, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a special member function.
|
|
consteval auto is_special_member_function(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_special_member_function, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a user-provided function.
|
|
consteval auto is_user_provided(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_user_provided, r);
|
|
}
|
|
|
|
// Returns whether the reflected entity is a user-declared function.
|
|
consteval auto is_user_declared(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_user_declared, r);
|
|
}
|
|
|
|
// Returns a reflection of the value held by the provided argument.
|
|
template <typename T>
|
|
requires (!is_reference_v<T> &&
|
|
__metafunction(detail::__metafn_is_structural_type, ^^T))
|
|
consteval auto reflect_constant(T r) -> info {
|
|
return __metafunction(detail::__metafn_reflect_result, ^^T, r);
|
|
}
|
|
|
|
// Returns a reflection of the object designated by the provided argument.
|
|
template <typename T> requires (!is_function_v<remove_reference_t<T>>)
|
|
consteval auto reflect_object(T &r) -> info {
|
|
return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r);
|
|
}
|
|
|
|
// Returns a reflection of the object designated by the provided argument.
|
|
template <typename T> requires (is_function_v<remove_reference_t<T>>)
|
|
consteval auto reflect_function(T &r) -> info {
|
|
return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r);
|
|
}
|
|
|
|
// Representation of a data member which may be passed to 'data_member_spec'.
|
|
struct data_member_options {
|
|
struct name_type {
|
|
variant<u8string, string> impl;
|
|
|
|
template <typename T> requires constructible_from<u8string, T>
|
|
consteval name_type(T &&in) : impl(in_place_type<u8string>, in) {}
|
|
|
|
template <typename T> requires constructible_from<string, T>
|
|
consteval name_type(T &&in) : impl(in_place_type<string>, in) {}
|
|
|
|
private:
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunused-private-field"
|
|
info unused = ^^::;
|
|
#pragma clang diagnostic pop
|
|
};
|
|
|
|
optional<name_type> name = nullopt;
|
|
optional<int> alignment = nullopt;
|
|
optional<int> width = nullopt;
|
|
bool no_unique_address = false;
|
|
};
|
|
|
|
// Returns the alignment of the reflected entity.
|
|
consteval auto alignment_of(info r) -> size_t {
|
|
return __metafunction(detail::__metafn_alignment_of, r);
|
|
}
|
|
|
|
// Returns a reflection representing a description of a data member, which may
|
|
// be used with 'define_aggregate' to define a record type.
|
|
consteval auto data_member_spec(info member_type,
|
|
data_member_options options = {}) -> info {
|
|
if (!is_type(member_type))
|
|
throw "'member_type' must represent a type";
|
|
|
|
auto name = options.name.value_or(u8"").impl;
|
|
int alignment = options.alignment.value_or(0);
|
|
int width = options.width.value_or(0);
|
|
bool no_unique_address = options.no_unique_address;
|
|
|
|
auto validate = [&](auto name_string) {
|
|
if (width) {
|
|
if (alignment)
|
|
throw "Cannot specify both width and alignment for data member";
|
|
if (no_unique_address)
|
|
throw "Cannot specify both width and no_unique_address for data member";
|
|
if (width < 0)
|
|
throw "Cannot specify a negative width for data member";
|
|
if (!extract<bool>(substitute(^^is_integral_v, {member_type})) &&
|
|
!extract<bool>(substitute(^^is_enum_v, {member_type})))
|
|
throw "Bit field must have integral or enumeral type";
|
|
} else {
|
|
if (options.width.has_value() && !name_string.empty())
|
|
throw "Bit-fields of zero width must be unnamed";
|
|
}
|
|
|
|
if (alignment) {
|
|
if (alignment < int(alignment_of(member_type)))
|
|
throw "Cannot specify an alignment less than that of the member type";
|
|
if (alignment <= 0 || ((alignment - 1) & alignment))
|
|
throw "Alignment specifier must be a non-negative power of 2";
|
|
}
|
|
};
|
|
|
|
if (holds_alternative<u8string>(name)) {
|
|
const u8string &s = get<u8string>(name);
|
|
validate(s);
|
|
return __metafunction(detail::__metafn_data_member_spec,
|
|
member_type,
|
|
!s.empty(), s.size(), ^^const char8_t, s.data(),
|
|
options.alignment.has_value(), alignment,
|
|
options.width.has_value(), width,
|
|
no_unique_address);
|
|
} else {
|
|
const string &s = get<string>(name);
|
|
validate(s);
|
|
return __metafunction(detail::__metafn_data_member_spec,
|
|
member_type,
|
|
!s.empty(), s.size(), ^^const char, s.data(),
|
|
options.alignment.has_value(), alignment,
|
|
options.width.has_value(), width,
|
|
no_unique_address);
|
|
}
|
|
}
|
|
|
|
// Completes the definition of the record type reflected by 'class_type' with
|
|
// the members described by the reflections in the provided range.
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto define_aggregate(info class_type, R &&members) -> info {
|
|
if constexpr (ranges::contiguous_range<R>) {
|
|
return __metafunction(detail::__metafn_define_aggregate, class_type,
|
|
ranges::size(members), ranges::data(members));
|
|
} else {
|
|
vector vmembers = members | ranges::to<vector>();
|
|
return __metafunction(detail::__metafn_define_aggregate, class_type,
|
|
vmembers.size(), vmembers.data());
|
|
}
|
|
}
|
|
|
|
struct member_offset {
|
|
ptrdiff_t bytes;
|
|
ptrdiff_t bits;
|
|
|
|
constexpr auto total_bits() -> ptrdiff_t {
|
|
return bytes * CHAR_BIT + bits;
|
|
}
|
|
|
|
auto operator<=>(member_offset const&) const = default;
|
|
};
|
|
|
|
// Returns the offset of the reflected entity.
|
|
consteval auto offset_of(info r) -> member_offset {
|
|
return member_offset {
|
|
__metafunction(detail::__metafn_offset_of, ^^ptrdiff_t, r),
|
|
__metafunction(detail::__metafn_bit_offset_of, ^^ptrdiff_t, r)
|
|
};
|
|
}
|
|
|
|
// Returns the size of the reflected entity.
|
|
consteval auto size_of(info r) -> size_t {
|
|
return __metafunction(detail::__metafn_size_of, r);
|
|
}
|
|
|
|
// Returns the size of the reflected entity in bits.
|
|
consteval auto bit_size_of(info r) -> size_t {
|
|
return __metafunction(detail::__metafn_bit_size_of, r);
|
|
}
|
|
|
|
// Type trait wrappers
|
|
|
|
consteval auto is_void_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_void_v, {r}));
|
|
}
|
|
|
|
consteval auto is_null_pointer_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_null_pointer_v, {r}));
|
|
}
|
|
|
|
consteval auto is_integral_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_integral_v, {r}));
|
|
}
|
|
|
|
consteval auto is_floating_point_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_floating_point_v, {r}));
|
|
}
|
|
|
|
consteval auto is_array_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_array_v, {r}));
|
|
}
|
|
|
|
consteval auto is_pointer_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_pointer_v, {r}));
|
|
}
|
|
|
|
consteval auto is_lvalue_reference_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_lvalue_reference_v, {r}));
|
|
}
|
|
|
|
consteval auto is_rvalue_reference_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_rvalue_reference_v, {r}));
|
|
}
|
|
|
|
consteval auto is_member_object_pointer_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_member_object_pointer_v, {r}));
|
|
}
|
|
|
|
consteval auto is_member_function_pointer_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_member_function_pointer_v, {r}));
|
|
}
|
|
|
|
consteval auto is_enum_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_enum_v, {r}));
|
|
}
|
|
|
|
consteval auto is_union_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_union_v, {r}));
|
|
}
|
|
|
|
consteval auto is_function_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_function_v, {r}));
|
|
}
|
|
|
|
consteval auto is_reflection_type(info r) -> bool {
|
|
return r == ^^info;
|
|
}
|
|
|
|
consteval auto is_reference_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_reference_v, {r}));
|
|
}
|
|
|
|
consteval auto is_arithmetic_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_arithmetic_v, {r}));
|
|
}
|
|
|
|
consteval auto is_fundamental_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_fundamental_v, {r}));
|
|
}
|
|
|
|
consteval auto is_object_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_object_v, {r}));
|
|
}
|
|
|
|
consteval auto is_scalar_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_scalar_v, {r}));
|
|
}
|
|
|
|
consteval auto is_compound_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_compound_v, {r}));
|
|
}
|
|
|
|
consteval auto is_member_pointer_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_member_pointer_v, {r}));
|
|
}
|
|
|
|
consteval auto is_const_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_const_v, {r}));
|
|
}
|
|
|
|
consteval auto is_volatile_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_volatile_v, {r}));
|
|
}
|
|
|
|
consteval auto is_trivial_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivial_v, {r}));
|
|
}
|
|
|
|
consteval auto is_trivially_copyable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_copyable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_standard_layout_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_standard_layout_v, {r}));
|
|
}
|
|
|
|
consteval auto is_empty_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_empty_v, {r}));
|
|
}
|
|
|
|
consteval auto is_polymorphic_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_polymorphic_v, {r}));
|
|
}
|
|
|
|
consteval auto is_abstract_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_abstract_v, {r}));
|
|
}
|
|
|
|
consteval auto is_final_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_final_v, {r}));
|
|
}
|
|
|
|
consteval auto is_aggregate_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_aggregate_v, {r}));
|
|
}
|
|
|
|
consteval auto is_consteval_only_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_consteval_only_v, {r}));
|
|
}
|
|
|
|
consteval auto is_signed_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_signed_v, {r}));
|
|
}
|
|
|
|
consteval auto is_unsigned_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_unsigned_v, {r}));
|
|
}
|
|
|
|
consteval auto is_bounded_array_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_bounded_array_v, {r}));
|
|
}
|
|
|
|
consteval auto is_unbounded_array_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_unbounded_array_v, {r}));
|
|
}
|
|
|
|
consteval auto is_scoped_enum_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_scoped_enum_v, {r}));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_constructible_type(info type, R &&type_args) {
|
|
vector<info> args(from_range, type_args);
|
|
args.insert(args.begin(), type);
|
|
|
|
return extract<bool>(substitute(^^is_constructible_v, args));
|
|
}
|
|
|
|
consteval auto is_default_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_default_constructible_v, {r}));
|
|
}
|
|
|
|
consteval auto is_copy_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_copy_constructible_v, {r}));
|
|
}
|
|
|
|
consteval auto is_move_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_move_constructible_v, {r}));
|
|
}
|
|
|
|
consteval auto is_assignable_type(info dst, info src) -> bool {
|
|
return extract<bool>(substitute(^^is_assignable_v, {dst, src}));
|
|
}
|
|
|
|
consteval auto is_copy_assignable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_copy_assignable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_move_assignable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_move_assignable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_swappable_with_type(info dst, info src) -> bool {
|
|
return extract<bool>(substitute(^^is_swappable_with_v, {dst, src}));
|
|
}
|
|
|
|
consteval auto is_swappable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_swappable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_destructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_destructible_v, {r}));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_trivially_constructible_type(info type, R &&type_args) {
|
|
vector<info> args(from_range, type_args);
|
|
args.insert(args.begin(), type);
|
|
|
|
return extract<bool>(substitute(^^is_trivially_constructible_v, args));
|
|
}
|
|
|
|
consteval auto is_trivially_default_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_default_constructible_v,
|
|
{r}));
|
|
}
|
|
|
|
consteval auto is_trivially_copy_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_copy_constructible_v,
|
|
{r}));
|
|
}
|
|
|
|
consteval auto is_trivially_move_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_move_constructible_v,
|
|
{r}));
|
|
}
|
|
|
|
consteval auto is_trivially_assignable_type(info dst, info src) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_assignable_v, {dst, src}));
|
|
}
|
|
|
|
consteval auto is_trivially_copy_assignable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_copy_assignable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_trivially_move_assignable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_move_assignable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_trivially_destructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_trivially_destructible_v, {r}));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_nothrow_constructible_type(info type, R &&type_args) {
|
|
vector<info> args(from_range, type_args);
|
|
args.insert(args.begin(), type);
|
|
|
|
return extract<bool>(substitute(^^is_nothrow_constructible_v, args));
|
|
}
|
|
|
|
consteval auto is_nothrow_default_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_default_constructible_v, {r}));
|
|
}
|
|
|
|
consteval auto is_nothrow_copy_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_copy_constructible_v, {r}));
|
|
}
|
|
|
|
consteval auto is_nothrow_move_constructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_move_constructible_v, {r}));
|
|
}
|
|
|
|
consteval auto is_nothrow_assignable_type(info dst, info src) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_assignable_v, {dst, src}));
|
|
}
|
|
|
|
consteval auto is_nothrow_copy_assignable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_copy_assignable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_nothrow_move_assignable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_move_assignable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_nothrow_swappable_with_type(info dst, info src) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_swappable_with_v, {dst, src}));
|
|
}
|
|
|
|
consteval auto is_nothrow_swappable_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_swappable_v, {r}));
|
|
}
|
|
|
|
consteval auto is_nothrow_destructible_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_destructible_v, {r}));
|
|
}
|
|
|
|
// TODO(P2996): Not yet implemented in libc++.
|
|
/*consteval auto is_implicit_lifetime_type(info r) -> bool {
|
|
return extract<bool>(substitute(^^is_implicit_lifetime_v, {r}));
|
|
}*/
|
|
|
|
consteval auto has_virtual_destructor(info r) -> bool {
|
|
return extract<bool>(substitute(^^has_virtual_destructor_v, {r}));
|
|
}
|
|
|
|
consteval auto has_unique_object_representations(info r) -> bool {
|
|
return extract<bool>(substitute(^^has_unique_object_representations_v, {r}));
|
|
}
|
|
|
|
// TODO(P2996): Not yet implemented in libc++.
|
|
/*consteval auto reference_constructs_from_temporary(info r) -> bool {
|
|
return extract<bool>(substitute(^^reference_constructs_from_temporary_v,
|
|
{r}));
|
|
}*/
|
|
|
|
// TODO({2996): Not yet implemented in libc++.
|
|
/*consteval auto reference_converts_from_temporary(info r) -> bool {
|
|
return extract<bool>(substitute(^^reference_converts_from_temporary_v, {r}));
|
|
}*/
|
|
|
|
consteval auto rank(info r) -> size_t {
|
|
return extract<size_t>(substitute(^^rank_v, {r}));
|
|
}
|
|
|
|
consteval auto extent(info r, unsigned i = 0) -> size_t {
|
|
return extract<size_t>(substitute(^^extent_v, {r, reflect_constant(i)}));
|
|
}
|
|
|
|
consteval auto is_same_type(info r, info s) -> bool {
|
|
return extract<bool>(substitute(^^is_same_v, {r, s}));
|
|
}
|
|
|
|
consteval auto is_base_of_type(info r, info s) -> bool {
|
|
return extract<bool>(substitute(^^is_base_of_v, {r, s}));
|
|
}
|
|
|
|
consteval auto is_convertible_type(info r, info s) -> bool {
|
|
return extract<bool>(substitute(^^is_convertible_v, {r, s}));
|
|
}
|
|
|
|
consteval auto is_nothrow_convertible_type(info r, info s) -> bool {
|
|
return extract<bool>(substitute(^^is_nothrow_convertible_v, {r, s}));
|
|
}
|
|
|
|
// TODO(P2996): Not yet implemented in libc++.
|
|
/*consteval auto is_layout_compatible_type(info r, info s) -> bool {
|
|
return extract<bool>(substitute(^^is_layout_compatible_v, {r, s}));
|
|
}*/
|
|
|
|
// TODO(P2996): Not yet implemented in libc++.
|
|
/*consteval auto is_pointer_interconvertible_base_of_type(info r,
|
|
info s) -> bool {
|
|
return extract<bool>(substitute(^^is_pointer_interconvertible_base_of_v,
|
|
{r, s}));
|
|
}*/
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_invocable_type(info type, R &&args) {
|
|
vector<info> targs(from_range, args);
|
|
targs.insert(targs.begin(), type);
|
|
|
|
return extract<bool>(substitute(^^is_invocable_v, targs));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_invocable_r_type(info result, info type, R &&args) {
|
|
vector<info> targs(from_range, args);
|
|
targs.insert(targs.begin(), type);
|
|
targs.insert(targs.begin(), result);
|
|
|
|
return extract<bool>(substitute(^^is_invocable_r_v, targs));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_nothrow_invocable_type(info type, R &&args) {
|
|
vector<info> targs(from_range, args);
|
|
targs.insert(targs.begin(), type);
|
|
|
|
return extract<bool>(substitute(^^is_nothrow_invocable_v, targs));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto is_nothrow_invocable_r_type(info result, info type,
|
|
R &&args) {
|
|
vector<info> targs(from_range, args);
|
|
targs.insert(targs.begin(), type);
|
|
targs.insert(targs.begin(), result);
|
|
|
|
return extract<bool>(substitute(^^is_nothrow_invocable_r_v, targs));
|
|
}
|
|
|
|
consteval auto remove_const(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_const_t, {type})));
|
|
}
|
|
|
|
consteval auto remove_volatile(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_volatile_t, {type})));
|
|
}
|
|
|
|
consteval auto remove_cv(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_cv_t, {type})));
|
|
}
|
|
|
|
consteval auto add_const(info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^add_const_t, {type}));
|
|
}
|
|
|
|
consteval auto add_volatile(info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^add_volatile_t, {type}));
|
|
}
|
|
|
|
consteval auto add_cv(info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^add_cv_t, {type}));
|
|
}
|
|
|
|
consteval auto remove_reference(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_reference_t, {type})));
|
|
}
|
|
|
|
consteval auto add_lvalue_reference(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^add_lvalue_reference_t,
|
|
{type})));
|
|
}
|
|
|
|
consteval auto add_rvalue_reference(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^add_rvalue_reference_t,
|
|
{type})));
|
|
}
|
|
|
|
consteval auto make_signed(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^make_signed_t, {type})));
|
|
}
|
|
|
|
consteval auto make_unsigned(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^make_unsigned_t, {type})));
|
|
}
|
|
|
|
consteval auto remove_extent(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_extent_t, {type})));
|
|
}
|
|
|
|
consteval auto remove_all_extents(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_all_extents_t,
|
|
{type})));
|
|
}
|
|
|
|
consteval auto remove_pointer(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_pointer_t, {type})));
|
|
}
|
|
|
|
consteval auto add_pointer(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^add_pointer_t, {type})));
|
|
}
|
|
|
|
consteval auto remove_cvref(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^remove_cvref_t, {type})));
|
|
}
|
|
|
|
consteval auto decay(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^decay_t, {type})));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto common_type(R &&args) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^common_type_t, args)));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto common_reference(R &&args) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^common_reference_t, args));
|
|
}
|
|
|
|
consteval auto underlying_type(info type) -> info {
|
|
return detail::__workaround_expand_compiler_builtins(
|
|
detail::__underlying_entity_of(substitute(^^underlying_type_t, {type})));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto invoke_result(info type, R &&args) -> info {
|
|
vector<info> targs(from_range, args);
|
|
targs.insert(targs.begin(), type);
|
|
|
|
return detail::__underlying_entity_of(substitute(^^invoke_result_t, targs));
|
|
}
|
|
|
|
consteval auto unwrap_reference(info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^unwrap_reference_t,
|
|
{type}));
|
|
}
|
|
|
|
consteval auto unwrap_ref_decay(info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^unwrap_ref_decay_t,
|
|
{type}));
|
|
}
|
|
|
|
consteval auto tuple_size(info type) -> size_t {
|
|
return extract<size_t>(substitute(^^tuple_size_v, {type}));
|
|
}
|
|
|
|
consteval auto tuple_element(size_t index, info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^tuple_element_t,
|
|
{reflect_constant(index), type}));
|
|
}
|
|
|
|
consteval auto variant_size(info type) -> size_t {
|
|
return extract<size_t>(substitute(^^variant_size_v, {type}));
|
|
}
|
|
|
|
consteval auto variant_alternative(size_t index, info type) -> info {
|
|
return detail::__underlying_entity_of(substitute(^^variant_alternative_t,
|
|
{reflect_constant(index), type}));
|
|
}
|
|
|
|
|
|
namespace detail {
|
|
template <class T> struct __wrap_workaround { using type = T; };
|
|
consteval auto __workaround_expand_compiler_builtins(info type) -> info {
|
|
auto r = substitute(^^__wrap_workaround, {type});
|
|
r = members_of(r, access_context::unchecked())[0];
|
|
return detail::__underlying_entity_of(r);
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
#if __has_feature(parameter_reflection)
|
|
|
|
consteval auto parameters_of(info r) -> vector<info> {
|
|
using iterator =
|
|
__range_of_infos::iterator<__range_of_infos::front_parameter_of_fn,
|
|
__range_of_infos::next_parameter_of_fn,
|
|
__range_of_infos::map_identity_fn>;
|
|
using range = __range_of_infos::range<iterator>;
|
|
auto rng = range{r};
|
|
return vector<info>{rng.begin(), rng.end()};
|
|
}
|
|
|
|
consteval auto has_ellipsis_parameter(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_ellipsis_parameter, r);
|
|
}
|
|
|
|
consteval auto has_default_argument(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_default_argument, r);
|
|
}
|
|
|
|
consteval auto is_explicit_object_parameter(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_explicit_object_parameter, r);
|
|
}
|
|
|
|
consteval auto is_function_parameter(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_function_parameter, r);
|
|
}
|
|
|
|
consteval auto return_type_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_return_type_of, r);
|
|
}
|
|
|
|
consteval auto variable_of(info r) -> info {
|
|
return __metafunction(detail::__metafn_variable_of, r);
|
|
}
|
|
|
|
#endif // __has_feature(parameter_reflection)
|
|
|
|
#if __has_feature(annotation_attributes)
|
|
|
|
consteval auto annotations_of(info r) -> vector<info> {
|
|
using iterator =
|
|
__range_of_infos::iterator<__range_of_infos::front_annotation_of,
|
|
__range_of_infos::next_annotation_of,
|
|
__range_of_infos::map_identity_fn>;
|
|
using range = __range_of_infos::range<iterator>;
|
|
auto rng = range{r};
|
|
return vector<info>{rng.begin(), rng.end()};
|
|
}
|
|
|
|
consteval auto annotations_of(info r, info ty) -> vector<info> {
|
|
if (!is_type(ty))
|
|
throw "Expected a reflection of a type";
|
|
|
|
return annotations_of(r) | views::filter([=](info annot) {
|
|
return type_of(annot) == ty;
|
|
}) | ranges::to<vector>();
|
|
}
|
|
|
|
template<typename T>
|
|
consteval optional<T> annotation_of_type(info r) {
|
|
auto v = annotations_of(r, ^^T);
|
|
optional<T> result{};
|
|
for (info a: v) {
|
|
if (result.has_value()) {
|
|
if (extract<T>(a) != result) {
|
|
throw "inconsistent annotations";
|
|
}
|
|
} else {
|
|
result = extract<T>(a);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
consteval auto is_annotation(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_annotation, r);
|
|
}
|
|
|
|
consteval auto annotate(info entity, info val) -> info {
|
|
return __metafunction(detail::__metafn_annotate, entity, val);
|
|
}
|
|
|
|
#endif // __has_feature(annotation_attributes)
|
|
|
|
consteval auto has_inaccessible_nonstatic_data_members(
|
|
info r,
|
|
access_context ctx) -> bool {
|
|
return !ranges::all_of(
|
|
nonstatic_data_members_of(r, access_context::unchecked()),
|
|
[=](info m) { return is_accessible(m, ctx); });
|
|
}
|
|
|
|
consteval auto has_inaccessible_bases(info r, access_context ctx) -> bool {
|
|
return !ranges::all_of(bases_of(r, access_context::unchecked()),
|
|
[=](info b) { return is_accessible(b, ctx); });
|
|
}
|
|
|
|
// ===================================================
|
|
// Other bespoke functions (not proposed at this time)
|
|
// ===================================================
|
|
|
|
// Returns whether the visibility of the reflected entity was specified.
|
|
consteval auto is_access_specified(info r) -> bool {
|
|
return __metafunction(detail::__metafn_is_access_specified, r);
|
|
}
|
|
|
|
// Returns a reflection of the constant value obtained from calling
|
|
// target(args...)
|
|
template <reflection_range R = initializer_list<info>>
|
|
consteval auto reflect_invoke(info target, R &&args) -> info {
|
|
if constexpr (ranges::contiguous_range<R>) {
|
|
return __metafunction(detail::__metafn_reflect_invoke, target,
|
|
static_cast<info *>(nullptr), 0,
|
|
ranges::data(args), ranges::size(args));
|
|
} else {
|
|
vector vargs = args | ranges::to<vector>();
|
|
return __metafunction(detail::__metafn_reflect_invoke, target,
|
|
static_cast<info *>(nullptr), 0,
|
|
vargs.data(), vargs.size());
|
|
}
|
|
}
|
|
|
|
template <reflection_range R1 = initializer_list<info>,
|
|
reflection_range R2 = initializer_list<info>>
|
|
consteval auto reflect_invoke(info target, R1 &&targs, R2 &&args) -> info {
|
|
if constexpr (ranges::contiguous_range<R1>) {
|
|
if constexpr (ranges::contiguous_range<R2>) {
|
|
return __metafunction(detail::__metafn_reflect_invoke, target,
|
|
ranges::data(targs), ranges::size(targs),
|
|
ranges::data(args), ranges::size(args));
|
|
} else {
|
|
vector vargs = args | ranges::to<vector>();
|
|
return __metafunction(detail::__metafn_reflect_invoke, target,
|
|
ranges::data(targs), ranges::size(targs),
|
|
vargs.data(), vargs.size());
|
|
}
|
|
} else {
|
|
vector vtargs = targs | ranges::to<vector>();
|
|
if constexpr (ranges::contiguous_range<R2>) {
|
|
return __metafunction(detail::__metafn_reflect_invoke, target,
|
|
vtargs.data(), vtargs.size(),
|
|
ranges::data(args), ranges::size(args));
|
|
} else {
|
|
vector vargs = args | ranges::to<vector>();
|
|
return __metafunction(detail::__metafn_reflect_invoke, target,
|
|
vtargs.data(), vtargs.size(),
|
|
vargs.data(), vargs.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
// =========================
|
|
// Deprecated names and APIs
|
|
// =========================
|
|
|
|
template <typename Ty>
|
|
[[deprecated("separated into 'reflect_value', 'reflect_result', and "
|
|
"'reflect_function' in P2996R4")]]
|
|
consteval auto reflect_result(Ty r) -> info {
|
|
constexpr auto DTy = detail::__underlying_entity_of(^^Ty);
|
|
constexpr auto RTy = is_class_v<typename [:DTy:]> ||
|
|
is_reference_v<typename [:DTy:]> ?
|
|
DTy : ^^remove_cv_t<typename [:DTy:]>;
|
|
|
|
return __metafunction(detail::__metafn_reflect_result,
|
|
detail::__underlying_entity_of(RTy),
|
|
static_cast<typename [:DTy:]>(r));
|
|
}
|
|
|
|
template <typename T>
|
|
[[deprecated("renamed to 'reflect_constant' in P2996R12")]]
|
|
consteval auto reflect_value(const T &r) -> info {
|
|
return reflect_constant(r);
|
|
}
|
|
|
|
[[deprecated("renamed to 'constant_of' in P2996R12")]]
|
|
consteval auto value_of(info r) -> info {
|
|
return constant_of(r);
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
[[deprecated("removed 'test_type' and 'test_types' in P2996R4")]]
|
|
consteval auto test_types(info templ, R &&args) -> bool {
|
|
return extract<bool>(substitute(templ, args));
|
|
}
|
|
|
|
[[deprecated("removed 'test_type' and 'test_types' in P2996R4")]]
|
|
consteval auto test_type(info templ, info type) -> bool {
|
|
info args[1] = {type};
|
|
return extract<bool>(substitute(templ, args));
|
|
}
|
|
|
|
[[deprecated("removed 'test_trait' in P2996R5")]]
|
|
consteval auto test_trait(info templ, info type) -> bool {
|
|
info args[1] = {type};
|
|
return extract<bool>(substitute(templ, args));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
[[deprecated("removed 'test_trait' in P2996R5")]]
|
|
consteval auto test_trait(info templ, R &&args) -> bool {
|
|
return extract<bool>(substitute(templ, args));
|
|
}
|
|
|
|
template <reflection_range R = initializer_list<info>>
|
|
[[deprecated("renamed to 'define_aggregate' in P2996R8")]]
|
|
consteval auto define_class(info class_type, R &&members) -> info {
|
|
return define_aggregate(class_type, members);
|
|
}
|
|
|
|
[[deprecated("P3547 requires an 'access_context' argument "
|
|
"(compile with '-fno-access-contexts' to disable this warning)")]]
|
|
consteval auto members_of(info r) -> vector<info> {
|
|
return members_of(r, access_context::unchecked());
|
|
}
|
|
|
|
[[deprecated("P3547 requires an 'access_context' argument "
|
|
"(compile with '-fno-access-contexts' to disable this warning)")]]
|
|
consteval auto bases_of(info r) -> vector<info> {
|
|
return bases_of(r, access_context::unchecked());
|
|
}
|
|
|
|
[[deprecated("P3547 requires an 'access_context' argument "
|
|
"(compile with '-fno-access-contexts' to disable this warning)")]]
|
|
consteval auto static_data_members_of(info r) -> vector<info> {
|
|
return static_data_members_of(r, access_context::unchecked());
|
|
}
|
|
|
|
[[deprecated("P3547 requires an 'access_context' argument "
|
|
"(compile with '-fno-access-contexts' to disable this warning)")]]
|
|
consteval auto nonstatic_data_members_of(info r) -> vector<info> {
|
|
return nonstatic_data_members_of(r, access_context::unchecked());
|
|
}
|
|
|
|
[[deprecated("replaced with 'is_enumerable_type' in P2996R11")]]
|
|
consteval auto has_complete_definition(info r) -> bool {
|
|
return __metafunction(detail::__metafn_has_complete_definition, r);
|
|
}
|
|
|
|
namespace __define_static {
|
|
|
|
template <typename ValTy, ValTy... Vals>
|
|
inline constexpr ValTy FixedArray[sizeof...(Vals)] = {Vals...};
|
|
|
|
} // namespace __define_static
|
|
|
|
template <ranges::input_range R>
|
|
requires (is_constructible_v<ranges::range_value_t<R>,
|
|
ranges::range_reference_t<R>>)
|
|
consteval auto reflect_constant_array(R &&elems) -> info {
|
|
using ValTy = ranges::range_value_t<R>;
|
|
vector Args = {^^ValTy};
|
|
for (const auto &V : elems)
|
|
Args.push_back(reflect_constant(V));
|
|
return substitute(^^__define_static::FixedArray, Args);
|
|
}
|
|
|
|
_LIBCPP_END_NAMESPACE_REFLECTION_V2
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
template <ranges::input_range R>
|
|
requires (is_constructible_v<ranges::range_value_t<R>,
|
|
ranges::range_reference_t<R>>)
|
|
consteval auto define_static_array(R &&elems)
|
|
-> span<const ranges::range_value_t<R>> {
|
|
using ValTy = ranges::range_value_t<R>;
|
|
meta::info array = meta::reflect_constant_array(elems);
|
|
return span<const ValTy>(extract<const ValTy*>(array), meta::extent(type_of(array)));
|
|
}
|
|
|
|
// Returns a static string having the provided contents.
|
|
consteval auto define_static_string(string_view in) -> const char * {
|
|
const char nullterm[1] = {0};
|
|
vector<span<const char>> v = {in, nullterm};
|
|
return define_static_array(views::join(v)).data();
|
|
}
|
|
|
|
consteval auto define_static_string(u8string_view in) -> const char8_t * {
|
|
const char8_t nullterm[1] = {0};
|
|
vector<span<const char8_t>> v = {in, nullterm};
|
|
return define_static_array(views::join(v)).data();
|
|
}
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2
|
|
|
|
// ====================================
|
|
// (u8)display_string_of implementation
|
|
// ====================================
|
|
|
|
// For the sake of compile-times, this probably would be better off being
|
|
// implemented as an intrinsic - but it ought to be possible to use P2996 to
|
|
// implement something like it, and the exercise of implementing it as a
|
|
// library has revealed both gaps in the paper and bugs in the implementation.
|
|
//
|
|
// For now, seeing as Clang/P2996 is still first and foremost a prototype, the
|
|
// implementation stands as both a "test" of the power of the APIs proposed by
|
|
// the paper, and a demonstratation of some reflection techniques.
|
|
|
|
namespace detail {
|
|
|
|
template <typename CharT>
|
|
struct pretty_printer {
|
|
static_assert(detail::__underlying_entity_of(^^CharT) == ^^char ||
|
|
detail::__underlying_entity_of(^^CharT) == ^^char8_t);
|
|
static constexpr bool IsUtf8 = is_same_type(^^CharT, ^^char8_t);
|
|
|
|
using string_t = basic_string<CharT>;
|
|
|
|
static consteval const CharT *string_constant(string_view contents) {
|
|
if constexpr (IsUtf8) {
|
|
u8string result(contents.size(), 0);
|
|
for (size_t idx = 0; char c : contents)
|
|
result[idx++] = char8_t(c);
|
|
|
|
return define_static_string(result);
|
|
} else {
|
|
return contents.data();
|
|
}
|
|
}
|
|
|
|
static consteval auto identifier_helper(info R) {
|
|
if constexpr (IsUtf8)
|
|
return u8identifier_of(R);
|
|
else
|
|
return identifier_of(R);
|
|
}
|
|
|
|
static consteval auto operator_symbol_helper(operators Op) {
|
|
if constexpr (IsUtf8)
|
|
return u8symbol_of(Op);
|
|
else
|
|
return symbol_of(Op);
|
|
}
|
|
|
|
template <info R>
|
|
static consteval info type_of_object_from_memptr() {
|
|
return []<typename T,
|
|
typename C>(T C::*) { return ^^C; }(typename [:R:]{});
|
|
};
|
|
|
|
template <info R>
|
|
static consteval info type_of_member_from_memptr() {
|
|
return []<typename T,
|
|
typename C>(T C::*) { return ^^T; }(typename [:R:]{});
|
|
};
|
|
|
|
template<auto... vals>
|
|
struct replicator_type {
|
|
template<typename F>
|
|
constexpr void operator>>(F body) const {
|
|
(body.template operator()<vals>(), ...);
|
|
}
|
|
};
|
|
|
|
template<auto... vals>
|
|
static constexpr replicator_type<vals...> replicator = {};
|
|
|
|
template<typename R>
|
|
static consteval auto expand(R range) {
|
|
vector<info> args;
|
|
for (auto r : range) {
|
|
args.push_back(reflect_constant(r));
|
|
}
|
|
return substitute(^^replicator, args);
|
|
}
|
|
|
|
template <info R>
|
|
requires (has_template_arguments(R))
|
|
static consteval string_t render_template_argument_list_of();
|
|
|
|
template <info R>
|
|
requires (is_value(R))
|
|
static consteval string_t render_value_as_hex();
|
|
|
|
template <info R>
|
|
static consteval const CharT *tprint();
|
|
|
|
struct tprint_impl {
|
|
template <info R> // Null reflection.
|
|
requires (R == info{})
|
|
static consteval string_t render() {
|
|
return string_constant("(null-reflection)");
|
|
}
|
|
|
|
template <info R> // Values of fundamental type.
|
|
requires (is_value(R) && is_fundamental_type(type_of(R)))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Values of aggregate type.
|
|
requires (is_value(R) && is_aggregate_type(type_of(R)))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Values of pointer type.
|
|
requires (is_value(R) && is_pointer_type(type_of(R)))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Objects.
|
|
requires (is_object(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Variables, data members, enumerators.
|
|
requires (is_variable(R) || is_nonstatic_data_member(R) ||
|
|
is_enumerator(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Templates.
|
|
requires (is_template(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Namespaces.
|
|
requires (is_namespace(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Functions.
|
|
requires (is_function(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Value types.
|
|
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
|
|
!is_pointer_type(R) && !is_array_type(R) &&
|
|
!is_function_type(R) && !is_reference_type(R) &&
|
|
!is_member_pointer_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // CV-qualified non-function, non-arry types.
|
|
requires (is_type(R) && (is_const(R) || is_volatile(R)) &&
|
|
!is_array_type(R) && !is_function_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Reference types.
|
|
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
|
|
is_reference_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Unqualified array types.
|
|
requires (is_type(R) && is_array_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Function types.
|
|
requires (is_type(R) && is_function_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Non-function, non-member pointer types.
|
|
requires (is_type(R) && is_pointer_type(R) &&
|
|
!(is_const(R) || is_volatile(R)) &&
|
|
!is_function_type(remove_pointer(R)))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Function pointer types.
|
|
requires (is_type(R) && is_pointer_type(R) &&
|
|
is_function_type(remove_pointer(R)))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Pointer to data member types.
|
|
requires (is_type(R) && is_member_pointer_type(R) &&
|
|
!(is_const(R) || is_volatile(R)) &&
|
|
!is_member_function_pointer_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Pointer to member function types.
|
|
requires (is_type(R) && is_member_function_pointer_type(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Base specifiers.
|
|
requires (is_base(R))
|
|
static consteval string_t render();
|
|
|
|
template <info R> // Fallback.
|
|
static consteval string_t render();
|
|
};
|
|
|
|
static consteval const CharT *print(info R);
|
|
|
|
friend consteval auto display_string_of(info) -> string_view;
|
|
friend consteval auto u8display_string_of(info) -> u8string_view;
|
|
|
|
};
|
|
|
|
template <typename CharT>
|
|
consteval auto pretty_printer<CharT>::print(info R)
|
|
-> const CharT * {
|
|
return extract<const CharT *>(reflect_invoke(^^tprint,
|
|
{reflect_constant(R)}, {}));
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R>
|
|
requires (has_template_arguments(R))
|
|
consteval auto pretty_printer<CharT>::render_template_argument_list_of()
|
|
-> string_t {
|
|
string_t result;
|
|
|
|
if (template_arguments_of(R).empty())
|
|
return string_constant("<>");
|
|
|
|
size_t Idx = 0;
|
|
[:expand(template_arguments_of(R)):] >> [&]<auto TArg> {
|
|
result += (Idx++ < 1 ? string_constant("<") : string_constant(", "));
|
|
result += tprint_impl::template render<TArg>();
|
|
};
|
|
return result + string_constant(">");
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R>
|
|
requires (is_value(R))
|
|
consteval auto pretty_printer<CharT>::render_value_as_hex() -> string_t {
|
|
string_t result = string_constant("0x");
|
|
|
|
auto bytes = bit_cast<array<unsigned char, size_of(type_of(R))>>([:R:]);
|
|
if (endian::native == endian::little)
|
|
reverse(begin(bytes), end(bytes));
|
|
|
|
for (auto b : bytes) {
|
|
static constexpr char lookup[] = "0123456789ABCDEF";
|
|
result += lookup[(b & CharT(0xF0)) >> 4];
|
|
result += lookup[b & CharT(0x0F)];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R>
|
|
consteval auto pretty_printer<CharT>::tprint() -> const CharT * {
|
|
return define_static_string(tprint_impl::template render<R>());
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Values of fundamental type.
|
|
requires(is_value(R) && is_fundamental_type(type_of(R)))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result;
|
|
constexpr info Ty = detail::__underlying_entity_of(type_of(R));
|
|
|
|
if constexpr (Ty == ^^nullptr_t)
|
|
result = string_constant("nullptr");
|
|
|
|
if constexpr (is_same_type(Ty, ^^bool)) {
|
|
if (extract<bool>(R))
|
|
result = string_constant("true");
|
|
else
|
|
result = string_constant("false");
|
|
}
|
|
|
|
else if constexpr (is_same_type(Ty, ^^char)) {
|
|
result = string_constant("'");
|
|
result.append(1, extract<char>(R));
|
|
result += string_constant("'");
|
|
}
|
|
|
|
else if constexpr (is_integral_type(Ty) &&
|
|
detail::__underlying_entity_of(^^CharT) == ^^char) {
|
|
CharT buffer[32] = {};
|
|
if (!to_chars(begin(buffer), end(buffer), [:R:]))
|
|
throw "'to_chars' failed to format integeral value";
|
|
result = buffer;
|
|
}
|
|
|
|
else if constexpr (is_floating_point_type(Ty)) {
|
|
result = render_value_as_hex<R>();
|
|
}
|
|
|
|
else {
|
|
result += string_constant("(value : ");
|
|
result += render<Ty>();
|
|
result += string_constant(")");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Values of aggregate type.
|
|
requires(is_value(R) && is_aggregate_type(type_of(R)))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result = render<type_of(R)>() + string_constant("{");
|
|
|
|
size_t Idx = 0;
|
|
[:expand(nonstatic_data_members_of(type_of(R),
|
|
access_context::unchecked())):] >>
|
|
[&]<auto Mem> {
|
|
if (Idx++ > 0) result += string_constant(", ");
|
|
result += tprint_impl::render<reflect_constant([:R:].[:Mem:])>();
|
|
};
|
|
result += string_constant("}");
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Values of pointer type.
|
|
requires (is_value(R) && is_pointer_type(type_of(R)))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
return string_constant("(value : ") + render<type_of(R)>() +
|
|
string_constant(")");
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Objects.
|
|
requires (is_object(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result = string_constant("(object : ");
|
|
result += render<type_of(R)>();
|
|
return result + string_constant(")");
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Templates.
|
|
requires(is_template(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
if constexpr (is_constructor_template(R))
|
|
return render<parent_of(R)>();
|
|
else if (is_operator_function_template(R)) {
|
|
operators op = operator_of(R);
|
|
|
|
string_t result = "operator";
|
|
switch (op) {
|
|
case operators::op_new:
|
|
case operators::op_delete:
|
|
case operators::op_array_new:
|
|
case operators::op_array_delete:
|
|
case operators::op_co_await:
|
|
result += " ";
|
|
[[fallthrough]];
|
|
default:
|
|
return result + operator_symbol_helper(op);
|
|
}
|
|
} else if (is_conversion_function_template(R))
|
|
return string_constant("(conversion-function-template)");
|
|
else if (is_literal_operator_template(R))
|
|
return string_constant(R"(operator"")") + string_t {identifier_helper(R) };
|
|
|
|
return string_t {identifier_helper(R)};
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Namespaces.
|
|
requires(is_namespace(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
if (R == ^^::)
|
|
return string_constant("(global-namespace)");
|
|
if (!has_identifier(R))
|
|
return string_constant("(anonymous-namespace)");
|
|
|
|
return string_t {identifier_helper(R)};
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Functions.
|
|
requires(is_function(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result;
|
|
|
|
if constexpr (has_template_arguments(R)) {
|
|
return render<template_of(R)>() + render_template_argument_list_of<R>();
|
|
} else if constexpr (is_destructor(R)) {
|
|
constexpr info P = parent_of(R);
|
|
return string_constant("~") +
|
|
render<has_template_arguments(P) ? template_of(P) : P>();
|
|
} else if constexpr (is_constructor(R)) {
|
|
return render<parent_of(R)>();
|
|
} else if constexpr (is_operator_function(R)) {
|
|
operators op = operator_of(R);
|
|
|
|
result = "operator";
|
|
switch (op) {
|
|
case operators::op_new:
|
|
case operators::op_delete:
|
|
case operators::op_array_new:
|
|
case operators::op_array_delete:
|
|
case operators::op_co_await:
|
|
result += " ";
|
|
[[fallthrough]];
|
|
default:
|
|
return result + operator_symbol_helper(op);
|
|
}
|
|
} else if constexpr (is_conversion_function(R)) {
|
|
#if __has_feature(parameter_reflection)
|
|
return string_constant("operator ") + render<return_type_of(R)>();
|
|
#else
|
|
return string_constant("conversion-function");
|
|
#endif
|
|
} else if constexpr (is_literal_operator(R)) {
|
|
return string_constant(R"(operator"")") + string_t {identifier_helper(R) };
|
|
}
|
|
|
|
return string_t {identifier_helper(R)};
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Value types.
|
|
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
|
|
!is_pointer_type(R) && !is_array_type(R) &&
|
|
!is_function_type(R) && !is_reference_type(R) &&
|
|
!is_member_pointer_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result;
|
|
|
|
if constexpr (has_template_arguments(R)) {
|
|
return render<template_of(R)>() + render_template_argument_list_of<R>();
|
|
} else if constexpr (is_fundamental_type(R)) {
|
|
if (R == ^^void) return string_constant("void");
|
|
|
|
if (R == ^^decltype(nullptr) || R == ^^nullptr_t)
|
|
return string_constant("std::nullptr_t");
|
|
if (R == ^^info || R == detail::__underlying_entity_of(^^info))
|
|
return string_constant("std::meta::info");
|
|
|
|
if (R == ^^bool) return string_constant("bool");
|
|
if (R == ^^signed char) return string_constant("signed char");
|
|
if (R == ^^unsigned char) return string_constant("unsigned char");
|
|
if (R == ^^char) return string_constant("char");
|
|
|
|
if (R == ^^char8_t) return string_constant("char8_t");
|
|
if (R == ^^char16_t) return string_constant("char16_t");
|
|
if (R == ^^char32_t) return string_constant("char32_t");
|
|
|
|
if (R == ^^float) return string_constant("float");
|
|
if (R == ^^double) return string_constant("double");
|
|
if (R == ^^long double) return string_constant("long double");
|
|
|
|
if (is_unsigned_type(R)) result += string_constant("unsigned ");
|
|
if constexpr (!is_type_alias(R)) {
|
|
auto U = make_signed(R);
|
|
if (U == ^^short) return result + string_constant("short");
|
|
if (U == ^^int) return result + string_constant("int");
|
|
if (U == ^^long) return result + string_constant("long");
|
|
if (U == ^^long long) return result + string_constant("long long");
|
|
}
|
|
}
|
|
|
|
if (has_identifier(R)) {
|
|
return string_t {identifier_helper(R)};
|
|
} else {
|
|
return string_constant("(anonymous type)");
|
|
}
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // CV-qualified non-function, non-array types.
|
|
requires (is_type(R) && (is_const(R) || is_volatile(R)) &&
|
|
!is_array_type(R) && !is_function_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result;
|
|
if (is_const(R))
|
|
result += string_constant("const ");
|
|
if (is_volatile(R))
|
|
result += string_constant("volatile ");
|
|
return result + render<remove_cv(R)>();
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Reference types.
|
|
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
|
|
is_reference_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result = render<remove_reference(R)>() + string_constant(" &");
|
|
if (is_rvalue_reference_type(R))
|
|
result += string_constant("&");
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Array types.
|
|
requires (is_type(R) && is_array_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result = render<remove_all_extents(R)>();
|
|
|
|
for (size_t k = 0; k < rank(R); ++k) {
|
|
CharT buffer[32] = {};
|
|
if (!to_chars(begin(buffer), end(buffer), extent(R, k)))
|
|
throw "'to_chars' failed to format integeral value";
|
|
|
|
result += "[" + string_t {buffer} + "]";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Non-function, non-member pointer types.
|
|
requires (is_type(R) && is_pointer_type(R) &&
|
|
!(is_const(R) || is_volatile(R)) &&
|
|
!is_function_type(remove_pointer(R)))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
return render<remove_pointer(R)>() + string_constant(" *");
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Function pointers.
|
|
requires (is_type(R) && is_pointer_type(R) &&
|
|
is_function_type(remove_pointer(R)))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
|
|
#if __has_feature(parameter_reflection)
|
|
constexpr auto FnTy = remove_pointer(R);
|
|
string_t result = render<return_type_of(FnTy)>() + string_constant("(*)(");
|
|
size_t Idx = 0;
|
|
[:expand(parameters_of(FnTy)):] >> [&]<auto Param> {
|
|
if (Idx++ > 0) result += string_constant(", ");
|
|
result += tprint_impl::render<Param>();
|
|
};
|
|
result += string_constant(")");
|
|
|
|
if (is_noexcept(FnTy))
|
|
result += string_constant(" noexcept");
|
|
#else
|
|
string_t result = string_constant("(function-pointer-type)");
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Function types.
|
|
requires (is_type(R) && is_function_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
#if __has_feature(parameter_reflection)
|
|
string_t result = render<return_type_of(R)>() + string_constant("(");
|
|
size_t Idx = 0;
|
|
[:expand(parameters_of(R)):] >> [&]<auto Param> {
|
|
if (Idx++ > 0) result += string_constant(", ");
|
|
result += tprint_impl::render<Param>();
|
|
};
|
|
result += string_constant(")");
|
|
|
|
if (is_const(R))
|
|
result += string_constant(" const");
|
|
if (is_volatile(R))
|
|
result += string_constant(" volatile");
|
|
|
|
if (is_lvalue_reference_qualified(R))
|
|
result += string_constant(" &");
|
|
else if (is_rvalue_reference_qualified(R))
|
|
result += string_constant(" &&");
|
|
|
|
if (is_noexcept(R))
|
|
result += string_constant(" noexcept");
|
|
#else
|
|
string_t result = string_constant("(function-type)");
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Pointer to data member types.
|
|
requires (is_type(R) && is_member_pointer_type(R) &&
|
|
!(is_const(R) || is_volatile(R)) &&
|
|
!is_member_function_pointer_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
string_t result = render<type_of_member_from_memptr<R>()>() +
|
|
string_constant(" ");
|
|
result += render<type_of_object_from_memptr<R>()>() + string_constant("::*");
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Pointer to member function types.
|
|
requires (is_type(R) && is_member_function_pointer_type(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
constexpr auto FnTy = type_of_member_from_memptr<R>();
|
|
|
|
#if __has_feature(parameter_reflection)
|
|
string_t result = render<return_type_of(FnTy)>() + string_constant("(");
|
|
result += render<type_of_object_from_memptr<R>()>() +
|
|
string_constant("::*)(");
|
|
|
|
size_t Idx = 0;
|
|
[:expand(parameters_of(FnTy)):] >> [&]<auto Param> {
|
|
if (Idx++ > 0) result += string_constant(", ");
|
|
result += tprint_impl::render<Param>();
|
|
};
|
|
result += string_constant(")");
|
|
|
|
if (is_const(FnTy))
|
|
result += string_constant(" const");
|
|
if (is_volatile(FnTy))
|
|
result += string_constant(" volatile");
|
|
|
|
if (is_lvalue_reference_qualified(FnTy))
|
|
result += string_constant(" &");
|
|
else if (is_rvalue_reference_qualified(FnTy))
|
|
result += string_constant(" &&");
|
|
|
|
if (is_noexcept(FnTy))
|
|
result += string_constant(" noexcept");
|
|
#else
|
|
string_t result = string_constant("(member-function-pointer-type)");
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
template <typename CharT>
|
|
template <info R> // Base specifiers.
|
|
requires (is_base(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
return string_t {render<type_of(R)>()};
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Fallback.
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
return string_constant("(unsupported-reflection)");
|
|
}
|
|
|
|
template <typename CharT>
|
|
template <info R> // Variables, data members, enumerators.
|
|
requires (is_variable(R) || is_nonstatic_data_member(R) || is_enumerator(R))
|
|
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
|
|
return string_t {identifier_helper(R)};
|
|
}
|
|
} // namespace detail
|
|
|
|
consteval auto display_string_of(info R) -> string_view {
|
|
return detail::pretty_printer<char>::print(R);
|
|
}
|
|
|
|
consteval auto u8display_string_of(info R) -> u8string_view {
|
|
return detail::pretty_printer<char8_t>::print(R);
|
|
}
|
|
|
|
_LIBCPP_END_NAMESPACE_REFLECTION_V2
|
|
|
|
#endif // __has_feature(reflection)
|
|
|
|
#endif // _LIBCPP_META
|