Detect existence of private member

后端 未结 2 1328
萌比男神i
萌比男神i 2020-12-29 20:27

I want to write a type trait to check if some type has a member member. If member were public, there are any number of ways to do this (e.

相关标签:
2条回答
  • 2020-12-29 20:58

    You can create another class MemberBase that does have that member, and then subclass the two classes (the class to check T and BaseMember) and try to access the member of the subclass. If T also has a member member, then you will get an ambiguity problem.

    Code:

    #include <type_traits>
    
    // Yakk's can_apply
    
    template<class...>struct voider{using type=void;};
    template<class...Ts>using void_t=typename voider<Ts...>::type;
    
    template<class...>struct types{using type=types;};
    namespace details {
      template<template<class...>class Z, class types, class=void>
      struct can_apply : std::false_type {};
      template<template<class...>class Z, class...Ts>
      struct can_apply< Z, types<Ts...>, void_t< Z<Ts...> > >:
        std::true_type
      {};
    }
    template<template<class...>class Z, class...Ts>
    using can_apply = details::can_apply<Z,types<Ts...>>;
    
    // Main code
    
    class MemberBase {
        public:
            int member;
    };
    
    template<class ToCheck>
    class MemberCheck: public ToCheck, public MemberBase {
    };
    
    template <typename T>
    using member_type = decltype(&T::member);
    
    template <typename T>
    using hasnot_member = can_apply<member_type, MemberCheck<T>>;
    
    template <typename T> 
    using static_not = std::integral_constant<bool, !T::value>;
    
    template <typename T>
    using has_member = static_not<hasnot_member<T>>;
    
    // Tests
    
    class A {
        int member;
    };
    
    class Ap {
        public:
        int member;
    };
    
    class B {
        float member;
    };
    
    class C {
        int member();
    };
    
    class D {
    };
    
    static_assert(has_member<A>{}, "!"); // ok
    static_assert(has_member<Ap>{}, "!"); // ok
    static_assert(has_member<B>{}, "!"); // ok
    static_assert(has_member<C>{}, "!"); // ok
    static_assert(has_member<D>{}, "!"); // fail
    

    However, this definitely smells like a dirty hack to me.

    0 讨论(0)
  • 2020-12-29 21:07

    There is indeed a way for non-final non-union class types:

    namespace detail {
        struct P {typedef int member;};
        template <typename U>
        struct test_for_member : U, P
        {
            template <typename T=test_for_member, typename = typename T::member>
            static std::false_type test(int);
            static std::true_type test(float);
        };
    }
    template <typename T>
    using test_for_member =
      std::integral_constant<bool, decltype(detail::test_for_member<T>::test(0)){}>;
    

    Demo. The trick is to check whether lookup into different base classes will yield an ambiguity. [class.member.lookup]/2:

    Member name lookup determines the meaning of a name (id-expression) in a class scope (3.3.7). Name lookup can result in an ambiguity, in which case the program is ill-formed. […] Name lookup takes place before access control (3.4, Clause 11).

    Note that GCCs lookup is broken insofar as it ignores non-type names for lookup in typename-specifiers.

    0 讨论(0)
提交回复
热议问题