Check if the function is callable

I use the is_callable structure defined as follows

 template <typename F, typename... Args> struct is_callable { template <typename U> static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type()); template <typename U> static auto test(...) -> decltype(std::false_type()); static constexpr bool value = decltype(test<F>(nullptr))::value; }; 

I use this to check lambda declared as:

 template <typename T> struct runner { T t; template <typename F, typename = typename std::enable_if<is_callable<F, T&>::value || is_callable<F, T&&>::value>::type> void run(F&& f) { return f(t); } }; runner<int> a{0}; a.run([&] (auto& x) { x++; }); 

Why does this compilation fail on enable_if on AppleClang? Should auto be displayed correctly?

+5
source share
2 answers

Your case for true_type test does not look right. Anyway, your code is more complicated than necessary. Try the following minimal working example:

 #include <utility> template<typename F, typename...Args> struct is_callable { template<typename F2, typename...Args2> static constexpr std::true_type test(decltype(std::declval<F2>()(std::declval<Args2>()...)) *) { return {}; } template<typename F2, typename...Args2> static constexpr std::false_type test(...) { return {}; } static constexpr bool value = decltype(test<F, Args...>(nullptr))::value; }; void f0(); static_assert(is_callable<decltype(f0)>::value, "f0()"); static_assert(!is_callable<decltype(f0), int>::value, "f0(0)"); int f1(int); static_assert(!is_callable<decltype(f1)>::value, "f1()"); static_assert(is_callable<decltype(f1), int>::value, "f1(0)"); static_assert(!is_callable<decltype(f1), int, int>::value, "f1(0, 0)"); auto __attribute__((unused)) f2 = [](int, char *) { return 7; }; static_assert(is_callable<decltype(f2), int, char *>::value, "f2(int, char *)"); static_assert(!is_callable<decltype(f2), int, int>::value, "f2(int, int)"); 
+1
source

The problem is not in the is_callable test class, but in your use.

When using std::enable_if in the argument list of a function template you should use it as follows:

 template <typename T> struct runner { T t; template < typename F, std::enable_if_t<is_callable<std::decay_t<F>, T&>::value || is_callable<F, T&&>::value>* = nullptr > void run(F&& f) { return f(t); } }; 

The form you tried to use is used to be used as a return return type:

  template<typename F> auto run(F&& f) -> std::enable_if_t<is_callable<std::decay_t<F>, T&>::value || is_callable<F, T&&>::value> { return f(t); } 

The is_callable type is_callable correct. It looks like the one I posted before before.

0
source

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


All Articles