oconnor0
oconnor0

Reputation: 3244

std::enable_if an argument is a function?

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

Answers (3)

SergeyA
SergeyA

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

T.C.
T.C.

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 to Args...

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

Barry
Barry

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 to Args...

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

Related Questions