Created
May 24, 2020 22:33
-
-
Save Innokentiy-Alaytsev/420c5a3361ad4b54c52bc27b1996ab4e to your computer and use it in GitHub Desktop.
"Has member" traits for member variables and functions, and nested types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <memory> | |
| #include <type_traits> | |
| #include <iostream> | |
| enum class MemberAccess { kProtected, kPublic }; | |
| #define GENERATE_MEMBER_ACCESSOR(...) \ | |
| template < class, AccessRequirement > \ | |
| struct MemberAccessor; \ | |
| \ | |
| \ | |
| template < class TTargetType_ > \ | |
| struct MemberAccessor< TTargetType_, AccessRequirement::kProtected > \ | |
| : public TTargetType_ { \ | |
| friend __VA_ARGS__; \ | |
| }; \ | |
| \ | |
| \ | |
| template < class TTargetType_ > \ | |
| struct MemberAccessor< TTargetType_, AccessRequirement::kPublic > \ | |
| : public TTargetType_ { \ | |
| }; \ | |
| \ | |
| \ | |
| static_assert (true, "Enforce semicolon after statement") | |
| #define CREATE_HAS_MEMBER_FUNCTION_TRAIT(i_member_name) \ | |
| template < class TType, MemberAccess KMemberAccess, class TSignature > \ | |
| struct HasMemberFunction_##i_member_name##_Trait { \ | |
| static_assert ( \ | |
| ::std::is_function_v< TSignature >, \ | |
| "TSignature must represent a function signature"); \ | |
| }; \ | |
| \ | |
| \ | |
| template < \ | |
| class TType, \ | |
| MemberAccess KMemberAccess, \ | |
| class TReturn, \ | |
| class... TArg > \ | |
| class HasMemberFunction_##i_member_name##_Trait< \ | |
| TType, \ | |
| KMemberAccess, \ | |
| TReturn (TArg...) > { \ | |
| struct ProtectedAccessor : public TType { \ | |
| friend class HasMemberFunction_##i_member_name##_Trait< \ | |
| TType, \ | |
| KMemberAccess, \ | |
| TReturn (TArg...) >; \ | |
| }; \ | |
| \ | |
| \ | |
| using TargetType = ::std::conditional_t< \ | |
| MemberAccess::kProtected == KMemberAccess, \ | |
| ProtectedAccessor, \ | |
| TType >; \ | |
| \ | |
| \ | |
| template < class TType_ > \ | |
| static constexpr auto Check (TType_*) -> typename ::std::conjunction< \ | |
| ::std::is_member_function_pointer< \ | |
| decltype (&TType_::i_member_name) >, \ | |
| ::std::is_same< \ | |
| TReturn, \ | |
| decltype (::std::declval< TType_ > ().i_member_name ( \ | |
| ::std::declval< TArg > ()...)) > >::type; \ | |
| \ | |
| static constexpr ::std::false_type Check (...); \ | |
| \ | |
| \ | |
| public: \ | |
| static auto constexpr value = \ | |
| decltype (Check (::std::declval< TargetType* > ()))::value; \ | |
| }; \ | |
| \ | |
| \ | |
| template < \ | |
| class TType, \ | |
| MemberAccess KMemberAccess, \ | |
| class TMemberSignature > \ | |
| static auto constexpr HasMemberFunction_##i_member_name = \ | |
| HasMemberFunction_##i_member_name##_Trait< \ | |
| TType, \ | |
| KMemberAccess, \ | |
| TMemberSignature >::value; \ | |
| \ | |
| \ | |
| static_assert (true, "Enforce semicolon after statement") | |
| #define CREATE_HAS_MEMBER_VARIABKE_TRAIT(i_member_name) \ | |
| template < class TType, MemberAccess KMemberAccess > \ | |
| class HasMemberVariable_##i_member_name##_Trait { \ | |
| struct ProtectedAccessor : public TType { \ | |
| friend class HasMemberVariable_##i_member_name##_Trait< \ | |
| TType, \ | |
| KMemberAccess >; \ | |
| }; \ | |
| \ | |
| \ | |
| using TargetType = ::std::conditional_t< \ | |
| MemberAccess::kProtected == KMemberAccess, \ | |
| ProtectedAccessor, \ | |
| TType >; \ | |
| \ | |
| \ | |
| template < class TType_ > \ | |
| static constexpr auto Check (TType_*) -> \ | |
| typename ::std::is_member_object_pointer< \ | |
| decltype (&TType_::i_member_name) >::type; \ | |
| \ | |
| static constexpr ::std::false_type Check (...); \ | |
| \ | |
| \ | |
| public: \ | |
| static auto constexpr value = \ | |
| decltype (Check (::std::declval< TargetType* > ()))::value; \ | |
| }; \ | |
| \ | |
| \ | |
| template < class TType, MemberAccess KMemberAccess > \ | |
| static auto constexpr HasMemberVariable_##i_member_name = \ | |
| HasMemberVariable_##i_member_name##_Trait< TType, KMemberAccess >:: \ | |
| value; \ | |
| \ | |
| \ | |
| static_assert (true, "Enforce semicolon after statement") | |
| #define CREATE_HAS_NESTED_TYPE_TRAIT(i_type_name, i_type_kind) \ | |
| template < class TType, MemberAccess KMemberAccess > \ | |
| class HasNested_##i_type_kind##_##i_type_name##_Trait { \ | |
| struct ProtectedAccessor : public TType { \ | |
| friend class HasNested_##i_type_kind##_##i_type_name##_Trait< \ | |
| TType, \ | |
| KMemberAccess >; \ | |
| }; \ | |
| \ | |
| \ | |
| using TargetType = ::std::conditional_t< \ | |
| MemberAccess::kProtected == KMemberAccess, \ | |
| ProtectedAccessor, \ | |
| TType >; \ | |
| \ | |
| \ | |
| template < class TType_ > \ | |
| using TypeKindTrait = ::std::is_##i_type_kind< TType_ >; \ | |
| \ | |
| \ | |
| template < class TType_ > \ | |
| static constexpr auto Check (TType_*) -> \ | |
| typename TypeKindTrait< typename TType_::i_type_name >::type; \ | |
| \ | |
| static constexpr ::std::false_type Check (...); \ | |
| \ | |
| \ | |
| public: \ | |
| static auto constexpr value = \ | |
| decltype (Check (::std::declval< TargetType* > ()))::value; \ | |
| }; \ | |
| \ | |
| \ | |
| template < class TType, MemberAccess KMemberAccess > \ | |
| static auto constexpr HasNested_##i_type_kind##_##i_type_name = \ | |
| HasNested_##i_type_kind##_##i_type_name##_Trait< \ | |
| TType, \ | |
| KMemberAccess >::value; \ | |
| \ | |
| \ | |
| static_assert (true, "Enforce semicolon after statement") | |
| #define CREATE_HAS_NESTED_CLASS_TRAIT(i_type_name) \ | |
| CREATE_HAS_NESTED_TYPE_TRAIT (i_type_name, class) | |
| #define CREATE_HAS_NESTED_ENUM_TRAIT(i_type_name) \ | |
| CREATE_HAS_NESTED_TYPE_TRAIT (i_type_name, enum) | |
| #define CREATE_HAS_NESTED_UNION_TRAIT(i_type_name) \ | |
| CREATE_HAS_NESTED_TYPE_TRAIT (i_type_name, union) | |
| struct A { | |
| explicit A (int i_a): a{i_a} {} | |
| int a; | |
| }; | |
| struct B: public A{ | |
| using A::A; | |
| }; | |
| #define PRINT_EXPRESSION(i) std::cout << #i": " << (i) << '\n'; | |
| CREATE_HAS_MEMBER_FUNCTION_TRAIT(SomeFunc); | |
| CREATE_HAS_MEMBER_FUNCTION_TRAIT(OthFunc); | |
| CREATE_HAS_NESTED_CLASS_TRAIT(Nested); | |
| CREATE_HAS_NESTED_ENUM_TRAIT(Nested); | |
| CREATE_HAS_NESTED_UNION_TRAIT(Nested); | |
| CREATE_HAS_NESTED_CLASS_TRAIT(Enum); | |
| CREATE_HAS_NESTED_ENUM_TRAIT(Enum); | |
| CREATE_HAS_NESTED_UNION_TRAIT(Enum); | |
| CREATE_HAS_NESTED_CLASS_TRAIT(Union); | |
| CREATE_HAS_NESTED_ENUM_TRAIT(Union); | |
| CREATE_HAS_NESTED_UNION_TRAIT(Union); | |
| struct Y { | |
| int OthFunc() { | |
| return 0; | |
| } | |
| protected: | |
| struct Nested; | |
| enum class Enum{}; | |
| union Union; | |
| void SomeFunc() {} | |
| }; | |
| struct N { | |
| }; | |
| int main () { | |
| auto p = ::std::make_unique<A> (B{1}); | |
| PRINT_EXPRESSION ((HasNested_class_Nested<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_class_Nested<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_enum_Nested<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_enum_Nested<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_union_Nested<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_union_Nested<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_class_Enum<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_class_Enum<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_enum_Enum<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_enum_Enum<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_union_Enum<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_union_Enum<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_class_Union<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_class_Union<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_enum_Union<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_enum_Union<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_union_Union<Y, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasNested_union_Union<Y, MemberAccess::kPublic>)); | |
| PRINT_EXPRESSION ((HasNested_class_Nested<N, MemberAccess::kProtected>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_SomeFunc<Y, MemberAccess::kProtected, void()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_SomeFunc<Y, MemberAccess::kProtected, int()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_SomeFunc<Y, MemberAccess::kPublic, void()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_SomeFunc<Y, MemberAccess::kPublic, int()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_OthFunc<Y, MemberAccess::kProtected, void()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_OthFunc<Y, MemberAccess::kProtected, int()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_OthFunc<Y, MemberAccess::kPublic, void()>)); | |
| PRINT_EXPRESSION ((HasMemberFunction_OthFunc<Y, MemberAccess::kPublic, int()>)); | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://godbolt.org/z/CtaEvP