@@ -347,43 +347,33 @@ struct unwrap_annotated<T> {
347347// ===================================================================
348348
349349template <typename T, std::size_t I>
350+ consteval bool has_alias_attr () {
351+ using field_t = refl::field_type<T, I>;
352+ if constexpr (!serde::has_attrs<field_t >) {
353+ return false ;
354+ } else {
355+ return serde::detail::tuple_any_of_v<typename field_t ::attrs, serde::is_alias_attr>;
356+ }
357+ }
358+
359+ // Primary template: field has no alias attribute.
360+ template <typename T, std::size_t I, bool HasAlias = has_alias_attr<T, I>()>
350361struct alias_storage {
351- constexpr static bool has_alias = [] {
352- using field_t = refl::field_type<T, I>;
353- if constexpr (!serde::has_attrs<field_t >) {
354- return false ;
355- } else {
356- return serde::detail::tuple_any_of_v<typename field_t ::attrs, serde::is_alias_attr>;
357- }
358- }();
362+ constexpr static bool has_alias = false ;
363+ constexpr static std::size_t count = 0 ;
364+ constexpr static std::array<std::string_view, 0 > names = {};
365+ };
359366
360- constexpr static std::size_t count = [] {
361- using field_t = refl::field_type<T, I>;
362- if constexpr (!serde::has_attrs<field_t >) {
363- return std::size_t {0 };
364- } else if constexpr (!serde::detail::tuple_any_of_v<typename field_t ::attrs,
365- serde::is_alias_attr>) {
366- return std::size_t {0 };
367- } else {
368- using alias_attr =
369- serde::detail::tuple_find_t <typename field_t ::attrs, serde::is_alias_attr>;
370- return alias_attr::names.size ();
371- }
372- }();
367+ // Specialization: field has an alias attribute — safe to access field_t::attrs.
368+ template <typename T, std::size_t I>
369+ struct alias_storage <T, I, true > {
370+ constexpr static bool has_alias = true ;
373371
374- constexpr static auto names = [] {
375- using field_t = refl::field_type<T, I>;
376- if constexpr (!serde::has_attrs<field_t >) {
377- return std::array<std::string_view, 0 >{};
378- } else if constexpr (!serde::detail::tuple_any_of_v<typename field_t ::attrs,
379- serde::is_alias_attr>) {
380- return std::array<std::string_view, 0 >{};
381- } else {
382- using alias_attr =
383- serde::detail::tuple_find_t <typename field_t ::attrs, serde::is_alias_attr>;
384- return alias_attr::names;
385- }
386- }();
372+ using field_t = refl::field_type<T, I>;
373+ using alias_attr = serde::detail::tuple_find_t <typename field_t ::attrs, serde::is_alias_attr>;
374+
375+ constexpr static std::size_t count = alias_attr::names.size();
376+ constexpr static auto names = alias_attr::names;
387377};
388378
389379// ===================================================================
@@ -641,12 +631,10 @@ struct enum_values_as_i64 {
641631 }();
642632};
643633
644- // / Declaration only — address known, value defined after virtual_schema.
634+ // / Forward declaration — full definition (with initializer) after virtual_schema.
645635// / Breaks self-referential constexpr cycles via declaration/definition separation.
646636template <typename V, typename Config>
647- struct struct_info_node {
648- const static struct_type_info value;
649- };
637+ struct struct_info_node ;
650638
651639} // namespace detail
652640
@@ -793,10 +781,12 @@ struct virtual_schema {
793781namespace detail {
794782
795783template <typename V, typename Config>
796- const struct_type_info struct_info_node<V, Config>::value = {
797- {type_kind::structure, refl::type_name<V>()},
798- {virtual_schema<V, Config>::fields.data (), virtual_schema<V, Config>::count},
799- virtual_schema<V, Config>::is_trivially_copyable,
784+ struct struct_info_node {
785+ const inline static struct_type_info value = {
786+ {type_kind::structure, refl::type_name<V>()},
787+ {virtual_schema<V, Config>::fields.data (), virtual_schema<V, Config>::count},
788+ virtual_schema<V, Config>::is_trivially_copyable,
789+ };
800790};
801791
802792} // namespace detail
0 commit comments