From 0a1b749691e91cbd08696d2f68e15aec7ea11715 Mon Sep 17 00:00:00 2001 From: Robert Patterson Date: Tue, 14 Jul 2026 06:13:25 -0500 Subject: [PATCH] fix: support optional member detection with MSVC Check that an optional field accessor exists before forming setter expressions that depend on its type. This prevents MSVC from instantiating references to absent generated core members while building mx::api. --- src/private/mx/utility/OptionalMembers.h | 63 ++++++++++++++---------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/private/mx/utility/OptionalMembers.h b/src/private/mx/utility/OptionalMembers.h index e89b18377..84fa5af00 100644 --- a/src/private/mx/utility/OptionalMembers.h +++ b/src/private/mx/utility/OptionalMembers.h @@ -101,22 +101,22 @@ \ template bool lookForAndSetHas##fieldNameCapitalized(bool has, T *const el) \ { \ - if constexpr (requires { el->setterName(std::nullopt); }) \ + if constexpr (requires { el->fieldName(); }) \ { \ - if (!has) \ + if constexpr (requires { el->setterName(std::nullopt); }) \ { \ - el->setterName(std::nullopt); \ + if (!has) \ + { \ + el->setterName(std::nullopt); \ + } \ + else if (!el->fieldName().has_value()) \ + { \ + el->setterName(typename std::decay_tfieldName())>::value_type{}); \ + } \ + return has; \ } \ - else if (!el->fieldName().has_value()) \ - { \ - el->setterName(typename std::decay_tfieldName())>::value_type{}); \ - } \ - return has; \ - } \ - else \ - { \ - return false; \ } \ + return false; \ } // Value setter for a clamped-decimal wrapper field. @@ -124,15 +124,18 @@ \ template void lookForAndSet##fieldNameCapitalized(VALUE_TYPE value, T *const el) \ { \ - if constexpr (requires { \ - el->setterName(typename std::decay_tfieldName())>::value_type{ \ - mx::core::Decimal{static_cast(value)}}); \ - }) \ + if constexpr (requires { el->fieldName(); }) \ { \ - if (el->fieldName().has_value()) \ + if constexpr (requires { \ + el->setterName(typename std::decay_tfieldName())>::value_type{ \ + mx::core::Decimal{static_cast(value)}}); \ + }) \ { \ - el->setterName(typename std::decay_tfieldName())>::value_type{ \ - mx::core::Decimal{static_cast(value)}}); \ + if (el->fieldName().has_value()) \ + { \ + el->setterName(typename std::decay_tfieldName())>::value_type{ \ + mx::core::Decimal{static_cast(value)}}); \ + } \ } \ } \ } @@ -142,13 +145,16 @@ \ template void lookForAndSet##fieldNameCapitalized(int value, T *const el) \ { \ - if constexpr (requires { \ - el->setterName(typename std::decay_tfieldName())>::value_type{value}); \ - }) \ + if constexpr (requires { el->fieldName(); }) \ { \ - if (el->fieldName().has_value()) \ + if constexpr (requires { \ + el->setterName(typename std::decay_tfieldName())>::value_type{value}); \ + }) \ { \ - el->setterName(typename std::decay_tfieldName())>::value_type{value}); \ + if (el->fieldName().has_value()) \ + { \ + el->setterName(typename std::decay_tfieldName())>::value_type{value}); \ + } \ } \ } \ } @@ -158,11 +164,14 @@ \ template void lookForAndSet##fieldNameCapitalized(VALUE_TYPE value, T *const el) \ { \ - if constexpr (requires { el->setterName(std::move(value)); }) \ + if constexpr (requires { el->fieldName(); }) \ { \ - if (el->fieldName().has_value()) \ + if constexpr (requires { el->setterName(std::move(value)); }) \ { \ - el->setterName(std::move(value)); \ + if (el->fieldName().has_value()) \ + { \ + el->setterName(std::move(value)); \ + } \ } \ } \ }