c++11 - C++ metafunction to determine whether a type is callable -
is possible write c++(0x) metafunction determines whether type callable?
by callable type mean function type, function pointer type, function reference type (these detected boost::function_types::is_callable_builtin
), lambda types, , class overloaded operator()
(and maybe class implicit conversion operator 1 of these, that's not absolutely necessary).
edit: metafunction should detect presence of operator()
signature, including templated operator()
. believe difficult part.
edit: here use case:
template <typename predicate1, typename predicate2> struct and_predicate { template <typename argt> bool operator()(const argt& arg) { return predicate1(arg) && predicate2(arg); } predicate1 predicate1; predicate2 predicate2; }; template <typename predicate1, typename predicate2> enable_if<ice_and<is_callable<predicate1>::value, is_callable<predicate2>::value>::value, and_predicate<predicate1, predicate2>>::type operator&&(predicate1 predicate1, predicate2 predicate2) { return and_predicate<predicate1, predicate2>{predicate1, predicate2}; }
is_callable
implement.
the presence of non-templated t::operator() given type t can detected by:
template<typename c> // detect regular operator() static char test(decltype(&c::operator())); template<typename c> // worst match static char (&test(...))[2]; static const bool value = (sizeof( test<t>(0) )
the presence of templated operator can detected by:
template<typename f, typename a> // detect 1-arg operator() static char test(int, decltype( (*(f*)0)( (*(a*)0) ) ) = 0); template<typename f, typename a, typename b> // detect 2-arg operator() static char test(int, decltype( (*(f*)0)( (*(a*)0), (*(b*)0) ) ) = 0); // ... detect n-arg operator() template<typename f, typename ...args> // worst match static char (&test(...))[2]; static const bool value = (sizeof( test<t, int>(0) ) == 1) || (sizeof( test<t, int, int>(0) ) == 1); // etc...
however, these 2 not play nicely together, decltype(&c::operator()) produce error if c has templated function call operator. solution run sequence of checks against templated operator first, , check regular operator() if , if templated 1 can not found. done specializing non-templated check no-op if templated 1 found.
template<bool, typename t> struct has_regular_call_operator { template<typename c> // detect regular operator() static char test(decltype(&c::operator())); template<typename c> // worst match static char (&test(...))[2]; static const bool value = (sizeof( test<t>(0) ) == 1); }; template<typename t> struct has_regular_call_operator<true,t> { static const bool value = true; }; template<typename t> struct has_call_operator { template<typename f, typename a> // detect 1-arg operator() static char test(int, decltype( (*(f*)0)( (*(a*)0) ) ) = 0); template<typename f, typename a, typename b> // detect 2-arg operator() static char test(int, decltype( (*(f*)0)( (*(a*)0), (*(b*)0) ) ) = 0); template<typename f, typename a, typename b, typename c> // detect 3-arg operator() static char test(int, decltype( (*(f*)0)( (*(a*)0), (*(b*)0), (*(c*)0) ) ) = 0); template<typename f, typename ...args> // worst match static char (&test(...))[2]; static const bool onearg = (sizeof( test<t, int>(0) ) == 1); static const bool twoarg = (sizeof( test<t, int, int>(0) ) == 1); static const bool threearg = (sizeof( test<t, int, int, int>(0) ) == 1); static const bool hastemplatedoperator = onearg || twoarg || threearg; static const bool value = has_regular_call_operator<hastemplatedoperator, t>::value; };
if arity one, discussed above, check should simpler. not see need additional type traits or library facilities work.
Comments
Post a Comment