The issue is here:
template <class InputIterator, class Function>
Function my_for_each(InputIterator first, InputIterator last, Function f)
invoked via:
my_for_each(vec_x.begin(), vec_x.end(), display);
This deduces Function
(of my_for_each
) to be a function pointer; for
void display(int& val)
the deduced type is void(*)(int&)
. The type trait std::is_function
however checks if the passed type is a function type, not a function pointer type.
One solution is to remove the pointer:
template<typename T>
constexpr bool Is_valid_function(T& a) {
return std::is_function<typename std::remove_pointer<T>::type>::value;
}
But, as clang++ reveals, this still isn't sufficient:
template<typename T>
void check_valid_function(T& a) {
static_assert(Is_valid_function(a), "Not The Valid Function");
}
a
as a function parameter (even if check_valid_function
was constexpr
!) is not a compile-time constant, therefore it may not appear in a constant expression (inside the function body). Hence, Is_valid_function(a)
may not appear as the check for the static_assert
. It might be possible to use something similar to declval
, e.g.
static_assert(Is_valid_function( declval<T&>() ), "Not The Valid Function");
but unfortunately, declval
is not constexpr
, and I don't know how to write a constexpr
version. So, you could pass a pointer instead:
static_assert(Is_valid_function(static_cast<T*>(nullptr)),
"Not a valid function");
For this, you need to rewrite Is_valid_function
as follows:
template<typename T>
constexpr bool Is_valid_function(T*) {
return std::is_function<typename std::remove_pointer<T>::type>::value;
}
Note: the passed argument here is a pointer to a pointer to a function, but the parameter T*
deduced T
to be a pointer to a function, as before (hence the change in the signature). You might want to reflect that in the function name, if you choose this solution.
Other issues:
Relying on ADL for Standard Library algorithms
return for_each(first, last, f) ;
As far as I can see, this relies on ADL. But the iterators (and the function) are not required to be in namespace
std
(even forvector::iterator
etc.), so you shouldn't rely on ADL:return std::for_each(first, last, f);
Use of non-const refs for functions that don't need to modify their arguments, e.g.
constexpr bool Is_valid_function(T& a)
If you don't need to modify an argument, you should either pass it by value or by const reference, e.g.
constexpr bool Is_valid_function(T const& a)
"Wrong check" If this code is just for educational purposes, this isn't an issue. However, the check if the passed argument is of a function type is the "wrong check" when trying to check if the argument valid for a Standard Library algorithm. You should rather check whether
f(*first)
is well-formed. This allows for function objects and checks if the argument type is "valid".