I'm trying to check whether a functor is compatible with a given set of parametertypes and a given return type (that is, the given parametertypes can be implicitely converted to the actual parametertypes and the other way around 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>
This works quite nicely in the majority of cases, however it fails to compile when I'm testing parameterless functors like struct foo{ int operator()() const;};
, beccause in that case the two operator()
of base are apperently ambigous, leading 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 a different way to check this for parameterless functors. I tried making a partial specialization of is_functor_compatible
for an empty parameterpack, where I check if the type of &T::operator()
is a parameterless memberfunction, which works more or less. However this approach obviously fails when the tested functor has several operator()
.
Therefore my question is if there is a better way to test for the existence of a parameterless operator()
and how to do it.
When I want to test if a given expression is valid for a type, I use a structure similar to this one:
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 };
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With