How to determine the presence of a static member function with a specific signature?

I found several questions and answers on SO dedicated to detecting at compile time (via SFINAE) whether a given class has a member of a particular name, type, or signature. However, I could not find one that also applies to static public member elements (when the tricks from the pointer to the element will not work). Any ideas?

+3
source share
3 answers

The following may help: ( https://ideone.com/nDlFUE )

#include <cstdint> #define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \ template <typename U> \ class traitsName \ { \ private: \ template<typename T, T> struct helper; \ template<typename T> \ static std::uint8_t check(helper<signature, &funcName>*); \ template<typename T> static std::uint16_t check(...); \ public: \ static \ constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \ } 

Then define the traits:

 DEFINE_HAS_SIGNATURE(has_foo, T::foo, void (*)(void)); 
+6
source

Here is one way:

 #include <type_traits> template<typename, typename> struct has_fun; template<typename T, typename Ret, typename... Args> struct has_fun<T, Ret(Args...)> { template<typename U, U> struct Check; template<typename U> static std::true_type Test(Check<Ret(*)(Args...), &U::fun>*); template<typename U> static std::false_type Test(...); static const bool value = decltype(Test<T>(0))::value; }; 

It is written for a function called fun . Use it as has_fun<T, int(int, int)>::value .

Here is another:

 #include <type_traits> template<typename, typename> struct has_fun; template<typename T, typename Ret, typename... Args> struct has_fun<T, Ret(Args...)> { struct No {}; // need a unique type for the second overload // so it doesn't match Ret and give a false positive template<typename U> static auto Test(int) -> decltype( U::fun(std::declval<Args>()...) ); template<typename U> static No Test(...); static const bool value = std::is_same<decltype(Test<U>(0)), Ret>{}; }; 

It might be wise to check if the return type of the function is convertible to Ret instead of checking for conformance. Use is_same instead of is_same in this case and at the same time check that the return type is different from No (as Yakk points out, there are types that can be built from almost anything).

+5
source

Just call the member function and discard the result in the SFINAE context. If this succeeds, the method exists. If this fails, the method does not work.

 // not needed in C++1y template<class T,class V=void>using enable_if_t=typename enable_if<T,V>::type; // If the other tests fail, the type T does not have a method `foo` of // signature Sig. The class=void parameter is an implementation detail // that in an industrial quality implementation we would hide in a helper // template type. template<class T,class Sig,class=void>struct has_foo:std::false_type{}; // For R(Args...), we attempt to invoke `T::foo` with (Args...), then check // if we can assign the return value to a variable of type R. template<class T,class R,class...Args> struct has_foo<T,R(Args...), enable_if_t< // std:: in C++1y std::is_convertible< decltype( T::foo( std::declval<Args>()... ) ), R >::value && !std::is_same<R, void>::value > >: std::true_type {}; // for `void` return value, we only care if the function can be invoked, // no convertible test required: template<class T,class...Args> struct has_foo<T,void(Args...), decltype( void(T::foo( std::declval<Args>()... ) ) ) >: std::true_type {}; 

using:

  has_foo< bar, int(int) >::value 

which checks if int r = T::foo( 7 ) valid expression, and not for exact signature matching.

+5
source

Source: https://habr.com/ru/post/1011724/


All Articles