Promoting an overloaded C ++ function with a pointer to a function object

A C ++ 11 template function that takes a function object argument, e.g .:

template <typename F, typename T>
auto foo(F f, T x) -> decltype(f(x)) {
  return f(x);
}

      

can take a function like:

int succ(int i) { return i+1; }

      

and apply foo

to succ

and get result 10:

foo(succ,9);

      

Overloaded functions don't work, for example sin

:

foo(std::sin,0.5);

      

in GCC (4.7) with "failed to infer template parameter F".

(The provision sin<double>

only applies to btw complex types.) Yes, I can structure it directly:

template <typename T>
struct Sin {
  T operator()(T x) { return std::sin(x); }
};

      

Little:

foo(Sin<double>(),0.5);

      

My question is, is there an alternative that avoids the need for such a new definition; can only be used on the call site foo

?

+3


source to share


1 answer


For function pointers, you can simply enter the user type of the signature:

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);
}

      

Live example on Ideone .

foo

after replacement will be the void foo(void f(int), int x)

same as foo(void (*f)(int), int x)

. This provides a so-called "invocation context" that allows the compiler to select the correct overload. Obviously this only works well if the first parameter of the template is a function. To get around this limitation and make it more attractive (imho, atleast), you can provide a simple helper function:

template<class F>
auto get_overload(F f) -> decltype(f) { return f; }

      

Actually, you can only overload the parameter types, but this does not obviate the need to inject the type of the return type, as this again disables the calling context, since the type must be inferred.

Since you most likely (or most likely) only want this for function pointers, you can change it to this:



template<class F>
F* get_overload(F* f){ return f; }

      

They are still exactly the same thing. The only reason why the first version can't just have F

as a return type, which F

is void(int)

if you call it with get_overload<void(int)>(bar)

, and the standard doesn't allow you to return functions (yes, that is a function type). The function for the pointer conversion function ( void(int)

void(*)(int)

) is used only for parameters.


Since @VJovic deleted his answer for some reason, I'll just edit this to:

You can actually use a simple lambda instead of a function get_overload

. It will be about the same length character and much more comfortable and understandable. It will also be more efficient, since no pointers (functions) are involved, and the compiler is great at inline the call.

foo([](int i){ return bar(i); }, 5);

      

+8


source







All Articles