Reputation: 3244
Why does the following compile under C++11? (I know it won't link.) I would expect the std::enable_if
test to fail since 1()
is not a function type.
#include <type_traits>
template <typename Func, typename... Args>
typename std::enable_if<std::is_function<Func(Args...)>::value>::type
delegate(Func, Args...);
int main(void) {
delegate(1); // << Why does this line compile?
return 0;
}
Upvotes: 1
Views: 692
Reputation: 62603
The code you have written will always yield true. You probably meant std::is_function<Func>...
Though not sure, it seems like you do not need enable_if
at all, and you'd better of with a simple
template <class R, class... ARGS>
R delegate2(R (*fun)(ARGS...), ARGS...);
However, if I am wrong and enable_if
is a key to success in your case, here is how you can do this:
#include <type_traits>
template <typename Func, typename... Args>
typename std::enable_if<std::is_function<std::remove_pointer_t<Func>>::value>::type
delegate(Func, Args...);
void check(int);
int main(void) {
delegate(check, 10); // << good line compiles
delegate(10); // << this bad line does not
return 0;
}
Upvotes: 3
Reputation: 137425
Func
is int
, Args
is empty, so Func(Args...)
is int()
, i.e., "function of ()
returning int
".
Anything that is_function
returns true for can't be the type of a by-value function parameter, so it's not obvious what you want to do.
I was trying to get delegate to only be callable when
Func
is a function (preferably function pointer) that can be applied toArgs...
Use expression SFINAE for that.
template <typename Func, typename... Args>
auto delegate(Func f, Args... args) -> decltype(f(args...), void());
Depending on what you actually want to do, you may want to std::move
f
and args
.
Upvotes: 6
Reputation: 303337
Based on this comment:
I was trying to get delegate to only be callable when
Func
is a function (preferably function pointer) that can be applied toArgs...
you're using the wrong type trait. To check if Func
is callable with Args...
, you need to construct an expression that would actually call an instance of Func
with those arguments. For that, there's std::result_of_t
(in C++14, it becomes SFINAE friendly):
template <typename Func, typename... Args,
class R = std::result_of_t<Func(Args...)>>
R delegate(Func, Args...);
Or, in C++11, just write that out with decltype
and declval
:
template <typename Func, typename... Args,
class R = std::declval<Func>()(std::declval<Args>()...)>
R delegate(Func, Args...);
Upvotes: 2