#pragma once #include #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// //! Default implementation of wrapper traits you can specialize for your type template requires std::is_object_v struct TBasicWrapperTraits { static constexpr bool IsTrivialWrapper = true; using TUnwrapped = T; //! Default implementations just forward the argument template requires std::same_as, T> static constexpr decltype(auto) Unwrap(U&& wrapper) noexcept; static constexpr bool HasValue(const T& wrapper) noexcept; }; //////////////////////////////////////////////////////////////////////////////// //! Represents common denominator of every single value wrapper template requires std::is_object_v struct TWrapperTraits { public: static constexpr bool IsTrivialWrapper = TBasicWrapperTraits::IsTrivialWrapper; using TWrapped = T; using TUnwrapped = typename TBasicWrapperTraits::TUnwrapped; static constexpr bool HasValue(const T& wrapper) noexcept; static constexpr bool RecursiveHasValue(const T& wrapper) noexcept; template requires std::same_as, T> static constexpr decltype(auto) Unwrap(U&& wrapper); template requires std::same_as, T> static constexpr decltype(auto) RecursiveUnwrap(U&& wrapper); using TRecursiveUnwrapped = std::remove_cvref_t::RecursiveUnwrap(std::declval()))>; //! Unfortunatelly, clang is incapable of processing associated constraints if they depend //! on class information (e.g. aliases and static varibles) and written out-of-line. //! TODO(arkady-e1ppa): Add proper constraints when clang supports them: //! Wrap: std::same_as, TUnwrapped> //! RecursiveWrap: std::same_as, TRecursiveUnwrapped> //! Proper constructible_from checks? Easy for wrap, hard for recursive wrap. template static constexpr T Wrap(U&& unwrapped) noexcept; template static constexpr T RecursiveWrap(U&& unwrapped) noexcept; }; //////////////////////////////////////////////////////////////////////////////// template concept CNonTrivialWrapper = (!TBasicWrapperTraits::IsTrivialWrapper) && requires (T& wrapper, const T& const_wrapper) { typename TBasicWrapperTraits::TUnwrapped; { TBasicWrapperTraits::Unwrap(wrapper) } -> std::same_as::TUnwrapped&>; { TBasicWrapperTraits::Unwrap(std::move(wrapper)) } -> std::same_as::TUnwrapped&&>; { TBasicWrapperTraits::Unwrap(const_wrapper) } -> std::same_as::TUnwrapped&>; { TBasicWrapperTraits::HasValue(const_wrapper) } -> std::same_as; }; //////////////////////////////////////////////////////////////////////////////// } // namespace NYT #define WRAPPER_TRAITS_INL_H_ #include "wrapper_traits-inl.h" #undef WRAPPER_TRAITS_INL_H_