升级C++重载函数指针到函数对象

use*_*370 3 c++ functor c++11

一个C++ 11模板函数,它接受一个函数对象参数,例如:

template <typename F, typename T>
auto foo(F f, T x) -> decltype(f(x)) {
  return f(x);
}
Run Code Online (Sandbox Code Playgroud)

可以采取如下功能:

int succ(int i) { return i+1; }
Run Code Online (Sandbox Code Playgroud)

并适用foosucc和获得的10结果:

foo(succ,9);
Run Code Online (Sandbox Code Playgroud)

重载的函数不起作用,sin例如,失败:

foo(std::sin,0.5);
Run Code Online (Sandbox Code Playgroud)

在GCC(4.7)中,"无法推导出模板参数F".

(提供sin<double>仅涉及复杂类型btw.)是的,我可以正确构建它:

template <typename T>
struct Sin {
  T operator()(T x) { return std::sin(x); }
};
Run Code Online (Sandbox Code Playgroud)

一点点:

foo(Sin<double>(),0.5);
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否存在一种避免需要这种新定义的替代方案; 仅在呼叫站点使用foo

Xeo*_*Xeo 8

对于函数指针,您只需让用户键入签名:

template<class F, class T>
void foo(F f, T x){
  f(x);
}

void bar(int){}
void bar(double){}

int main(){
  foo<void(int)>(bar, 5);
}
Run Code Online (Sandbox Code Playgroud)

Ideone上的实例.

foovoid foo(void f(int), int x)在替换后,这是相同的foo(void (*f)(int), int x).这提供了所谓的"调用上下文",允许编译器选择正确的重载.显然,只有当第一个模板参数是函数时,这才有效.要解决这个限制,并使其看起来更好(imho,至少),您可以提供一个简单的帮助函数:

template<class F>
auto get_overload(F f) -> decltype(f) { return f; }
Run Code Online (Sandbox Code Playgroud)

实际上,你只能重载参数类型,但是你不能剔除让用户输入返回类型的需要,因为这会再次禁用调用上下文,因为需要推导出一种类型.

由于您很可能(或肯定)只想要这个函数指针,您可以将其更改为:

template<class F>
F* get_overload(F* f){ return f; }
Run Code Online (Sandbox Code Playgroud)

它仍然完全相同.为什么第一个版本不能只是唯一的原因,F作为返回类型是,Fvoid(int),如果你把它get_overload<void(int)>(bar)和标准不允许你返回功能(是的,这是一个功能型).功能指针转换(void(int)- > void(*)(int))部分的功能仅适用于参数.


因为无论出于何种原因@VJovic删除了他的答案,我只会编辑:

您实际上可以使用简单的lambda而不是get_overload函数.它的性格大致相同,更方便,更清晰.它也会更高效,因为不涉及(函数)指针,编译器完全能够内联调用.

foo([](int i){ return bar(i); }, 5);
Run Code Online (Sandbox Code Playgroud)