How to check the existence type of a parameterless operator ()

I'm trying to check if a functor is compatible with a given set of parameter types and a given return type (i.e., given parameter types can be implicitly converted to actual parameter types and vice versa for the return type). Currently, I use the following code for this:

template<typename T, typename R, template<typename U, typename V> class Comparer> struct check_type { enum {value = Comparer<T, R>::value}; }; template<typename T, typename Return, typename... Args> struct is_functor_compatible { struct base: public T { using T::operator(); std::false_type operator()(...)const; }; enum {value = check_type<decltype(std::declval<base>()(std::declval<Args>()...)), Return, std::is_convertible>::value}; }; 

check_type<T, V, Comparer> In most cases this works very well, however it will not compile when I test parameterless functors such as struct foo{ int operator()() const;}; , beccause in this case, the two operator() bases are based on uncertainty, which leads to something like this:

 error: call of '(is_functor_compatible<foo, void>::base) ()' is ambiguous note: candidates are: note: std::false_type is_functor_compatible<T, Return, Args>::base::operator()(...) const [with T = foo, Return = void, Args = {}, std::false_type = std::integral_constant<bool, false>] note: int foo::operator()() const 

So obvoiusly I need another way to test this for parameterless functors. I tried to do a partial specialization of is_functor_compatible for an empty parameter, where I check if the &T::operator() a parameterless function that works more or less. However, this approach obviously fails when the functor under test has multiple operator() .

So my question is, is there a better way to check for existence without operator() parameters and how to do it.

+7
c ++ c ++ 11 templates metaprogramming
source share
2 answers

When I want to check if a given expression is valid for a type, I use a structure like this:

 template <typename T> struct is_callable_without_parameters { private: template <typename T1> static decltype(std::declval<T1>()(), void(), 0) test(int); template <typename> static void test(...); public: enum { value = !std::is_void<decltype(test<T>(0))>::value }; }; 
+8
source share

Have you tried something like:

 template<size_t> class Discrim { }; template<typename T> std::true_type hasFunctionCallOper( T*, Discrim<sizeof(T()())>* ); template<typename T> std::false_type hasFunctionCallOper( T*, ... ); 

After that, you recognize the return type hasFunctionCallOper((T*)0, 0) .

EDITED (thanks to the proposal of R. Martigno Fernandez):

Here is the code that works:

 template<size_t n> class CallOpDiscrim {}; template<typename T> TrueType hasCallOp( T*, CallOpDiscrim< sizeof( (*((T const*)0))(), 1 ) > const* ); template<typename T> FalseType hasCallOp( T* ... ); template<typename T, bool hasCallOp> class TestImpl; template<typename T> class TestImpl<T, false> { public: void doTellIt() { std::cout << typeid(T).name() << " does not have operator()" << std::endl; } }; template<typename T> class TestImpl<T, true> { public: void doTellIt() { std::cout << typeid(T).name() << " has operator()" << std::endl; } }; template<typename T> class Test : private TestImpl<T, sizeof(hasCallOp<T>(0, 0)) == sizeof(TrueType)> { public: void tellIt() { this->doTellIt(); } }; 
+3
source share

All Articles