Expression SFINAE to overload on type of passed function pointer

爷,独闯天下 提交于 2019-12-01 17:53:22

As has been mentioned before, SFINAE doesn't work because the names of overloaded functions have no definite type in C++, therefore template parameter substitution doesn't even happen at this stage.

However, in your example, the problem is arguably not that you have too many overloads of "foo", but too few overloads of "call". Just provide both the templates with typename F and the ones that expect a function pointer. The compiler will now be able to do the right thing depending on context:

#include <iostream>

// Functions
int foo() { return 0; }

int foo(int) { return 1; }

// Function object
struct Foo
{
    int operator()() const { return 2; }
    int operator()(int) const { return 3; }
};

// Higher-order functions / templates
template<typename F>
int call(F f) {
    return f();
}

int call(int (*f)()) {
    return f();
}

template<typename F, typename A>
int call(F f, A a) {
    return f(a);
}

template<typename A>
int call(int (*f)(A), A a) {
    return f(a);
}

int main()
{
    int a = call(foo)
      , b = call(foo, 0)
      , c = call(Foo())
      , d = call(Foo(), 0);
    std::cout << a << ',' << b << ',' << c << ',' << d << '\n';  // 0,1,2,3
}

The call overloads can be made more generic by adding return type deduction. In C++11, this is possible even with function objects by using decltype rsp. result_of. For brevity, I will post only the new function signatures, as the bodies don't need to be changed in this case:

template<typename F>
auto call(F f) -> decltype(f());

template<typename R>
R call(R (*f)());

template<typename F, typename A>
auto call(F f, A a) -> decltype(f(a));

template<typename R, typename A>
R call(R (*f)(A), A a);
n.m.

The closest you can get is probably this:

struct sfoo
{
  template<typename... args>
  void operator() (args&&... a)
  { 
    foo(std::forward<args>(a)...);
  }
};

and pass sfoo (or sfoo()) instead of foo around.

That is, create a function object type that encapsulates the entire overload set in the templatized operator().

Then instead of overload resolution over a template argument, which does not exist, you get a template instantiation over the same argument, which is OK.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!