Why std::is_function returns false for simple functions and lambdas?

From cppreference:

Checks whether T is a function type. Types like std::function, lambdas, classes with overloaded operator() and pointers to functions don't count as function types.

This answer explains that you also need to use std::remove_pointer<F>::type as the type since functions are converted to pointers to functions when passing by value. So your code should look like this:

template <typename F,
          typename = typename std::enable_if<
                                              std::is_function<
                                                typename std::remove_pointer<F>::type
                                              >::value
                                            >::type>
int fun( F f )
{
  return f(3);
}

Another way to approach this problem is to write a more specific type trait. This one, for example, checks that the argument types are convertible and works for anything that's callable.

#include <iostream>
#include <type_traits>
#include <utility>
#include <string>

template<class T, class...Args>
struct is_callable
{
    template<class U> static auto test(U*p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());

    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr auto value = decltype(test<T>(nullptr))::value;
};

template<class T, class...Args>
static constexpr auto CallableWith = is_callable<T, Args...>::value;


template <typename F,
std::enable_if_t<
CallableWith<F, int>
>* = nullptr
>
int fun( F f ) // line 8
{
    return f(3);
}

int l7(int x)
{
    return x%7;
}

int main()
{
    auto l = [](int x) -> int{
        return x%7;
    };

    std::cout << "fun(l) returns " << fun(l) << std::endl;

    std::cout << CallableWith<decltype(l7), int> << std::endl;    // prints 1
    std::cout << CallableWith<decltype(l7), float> << std::endl;  // prints 1 because float converts to int
    std::cout << CallableWith<decltype(l7), const std::string&> << std::endl; // prints 0
}