Skip to content

Instantly share code, notes, and snippets.

@Innokentiy-Alaytsev
Created May 24, 2020 22:33
Show Gist options
  • Select an option

  • Save Innokentiy-Alaytsev/420c5a3361ad4b54c52bc27b1996ab4e to your computer and use it in GitHub Desktop.

Select an option

Save Innokentiy-Alaytsev/420c5a3361ad4b54c52bc27b1996ab4e to your computer and use it in GitHub Desktop.
"Has member" traits for member variables and functions, and nested types
#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()>));
}
@Innokentiy-Alaytsev
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment