Detection of the presence of an arbitrary member

It is easy to write a template that will detect the presence of a specific element in a type using void_t :

 #include <type_traits> // This comes from cppreference template<typename... Ts> struct make_void { typedef void type;}; template<typename... Ts> using void_t = typename make_void<Ts...>::type; // primary template handles types that have no ::aMember template< class T, class = void_t<> > struct has_aMember : std::false_type { }; // specialization recognizes types that do have a ::aMember template< class T > struct has_aMember<T, void_t<decltype( T::aMember )>> : std::true_type { }; 

Now, if I want to determine if any other element is present, I would have to copy-paste the detector templates and simply change aMember to otherMember :

 template< class T, class = void_t<> > struct has_otherMember : std::false_type { }; template< class T > struct has_otherMember<T, void_t<decltype( T::otherMember )>> : std::true_type { }; 

I would like to avoid this copy and pass the member name as a parameter to a more general version of the discovery pattern:

 template< class T, class member, class = void_t<> > struct has_arbitrary_member : std::false_type { }; template< class T, class member > struct has_arbitrary_member<T, void_t<decltype( T::member )>> : std::true_type { }; 

so that I can use this has_arbitrary_member , passing the type and name of the member as a template parameter:

  std::cout << has_arbitrary_member<MyType, aMember>(); std::cout << has_arbitrary_member<MyType, otherMember>(); 

However, with the definition above, this will not compile. Is there any other way to implement such functionality?

+8
c ++ c ++ 11 templates c ++ 14
source share
2 answers

What you are trying to do is not possible at all, because you cannot suppress the search for names on aMember unless you change the flow of tokens using a macro. It follows that you will never be able to use a name that is not in scope unless you are inside SFINAE, which will suppress the error.

This means that you really need to write a separate template for each name.

This is one of those cases where using macros is not a bad idea, although it depends on whether you really need to check members of a particular name or if there are better ways to achieve your goal.

+7
source share

No, you cannot pass a member name as a template parameter without specifying which class / structure has a member name.

And if this class / structure does not have this member name, then the code has an error.

Now void_t< decltype( &MyType::some_member ) > either void or replacement failure depending on whether some_member . Often this solves the SFINAE problem where you do not need bool compilation time.

If you want the code to run if some type does not have a member, you can do this with a careful choice of overload order or specialized templates, etc.

It is not as strong as has_arbitrary_member<MyType, some_member> .

 template<class T> using some_member_type = decltype( std::declval<T>().some_member ); 

is a simple trait that with std :: experimental :: is_detected you can do:

 is_detected_v< some_member_type, T > 

or

 template<class T> constexpr bool has_some_member_v = is_detected_v< some_member_type, T >; 

which behaves like has_arbitrary_member<MyType, some_member> . I think this is best in practice.

+3
source share

All Articles