Let me check if
struct Thing { int foo(double, bool) {return 0;} };
has a member function int foo(double, bool) at compile time. There are many ways to do this, and most of them are just variations of others. Can someone think of how much different (or at least creative enough) than the 5 ways that I mention here? I'm just trying to learn some new methods with templates and SFINAE.
#include <iostream> #include <type_traits> // Using void_t (this includes using std::is_detected). template <typename T> using void_t = void; template <typename T, typename = void> struct has_foo : std::false_type {}; template <typename T> struct has_foo<T, void_t<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))> > : std::true_type {}; // Using the ... default argument. template <typename T> struct hasfoo { template <typename U> static std::true_type test (decltype(static_cast<int(T::*)(double, bool)>(&T::foo))*); // or 'decltype(static_cast<int>(std::declval<U>().foo(double{}, bool{})))*' works fine too. template <typename> static std::false_type test (...); static constexpr bool value = decltype(test<T>(nullptr))::value; }; // Overloads and trailing return types. template <typename> struct Helper : std::true_type {}; template <typename T> auto helper(int) -> Helper<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>; template <typename> std::false_type helper(long); template <typename T> constexpr bool hasFoo() {return decltype(helper<T>(0))::value;} // Comma operator (basically the same as the above). template <typename T> auto check(int) -> decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})), std::true_type{}); template <typename T> std::false_type check(...); template <typename T> using HasFoo = decltype(check<T>(0)); // Member function pointer template parameter. template <typename T> struct Hasfoo { template <typename U, int(U::*)(double, bool)> struct Tag; template <typename U> static constexpr bool test (Tag<U, &U::foo>*) {return true;} template <typename> static constexpr bool test (...) {return false;} static constexpr bool value = test<T>(nullptr); }; // Tests struct Thing { int foo(double, bool) {return 0;} }; int main() { static_assert (has_foo<Thing>::value, ""); static_assert (hasfoo<Thing>::value, ""); static_assert (hasFoo<Thing>(), ""); static_assert (HasFoo<Thing>::value, ""); }
Edit: I just remembered the elegant and more general solution that Jakk gave to another question quite recently (here is his actual typing, modified only to match the foo function):
namespace meta { namespace details { template<template<class...>class Z, class=void, class...Ts> struct can_apply : std::false_type {}; template<template<class...>class Z, class...Ts> struct can_apply<Z, decltype((void)(std::declval<Z<Ts...>>())), Ts...>: std::true_type {}; } template<template<class...>class Z, class...Ts> using can_apply = details::can_apply<Z,void,Ts...>; } template<class T> using member_foo = decltype(static_cast<int(T::*)(double, bool)>(&T::foo)); template<class T> using has_member_foo = meta::can_apply<member_foo, T>;
c ++ c ++ 11 templates sfinae
prestokeys
source share