How to get a pointer to the overload function that the compiler chooses?

How can I get a function pointer to an overloaded function that the compiler could select after checking the arguments? In this example:

#include <iostream> void MyFunction(float a){} void MyFunction(int a){} int main() { float a; MyFunction(a); void (*manualFunctionPointer)(float); manualFunctionPointer(a); // automaticFunctionPointer = ? } 

I pointed out that I need a pointer to a function that takes a float and returns void. The compiler can certainly figure this out on its own, because calling MyFunction (a) calls the correct function. Is there a way to get a pointer to a function that the compiler selects?

+4
source share
3 answers

Replace float in

 void (*manualFunctionPointer)(float); 

WITH

 void (*manualFunctionPointer)(decltype(a)); 

Then, regardless of the changes, manualFunctionPointer will follow

0
source
 #include <iostream> void MyFunction(float a){std::cout << "float\n";} void MyFunction(int a){std::cout << "int\n";} template<typename Func, typename T> void Do( Func f, T t ) { f(t); } template<typename T> void DoMyFunction( T t ) { Do(static_cast<void(*)(T)>(MyFunction), t); } template<typename T> void DoSomeFunction( T t, void(*func)(T) ) { Do(func, t); } int main() { float a; MyFunction(a); void (*manualFunctionPointer)(float) = MyFunction; manualFunctionPointer(a); // Do(MyFunction, a); -- does not compile Do(static_cast<void(*)(float)>(MyFunction), a); DoMyFunction(a); DoSomeFunction(a, MyFunction); } 

The above work. I chose MyFunction in four different ways.

If you want to make some kind of boiler and want to solve the "what if a is char " problem, this can help:

 // wrap the idea of calling MyFunction in a type: struct MyFunctionFunctor { template<typename T> static auto Do( T&& t )->decltype(MyFunction(std::forward(t))) { return MyFunction(std::forward(t)); } }; // Calling MyFunctionFunctor::Do( x ) will basically do static dispatch on all of // the overloads of MyFunction // wrap the idea of dispatching a variable to a functor: template<typename T, typename Functor> struct Dispatch { static auto Do( T t )->decltype( Functor::Do( t ) ) { return Functor::Do( t ); } } int main() { char a; auto func_ptr = &Dispatch<decltype(a), MyFunctionFunctor>::Do; func_ptr(a); } 

but, as noted, this requires us to wrap our MyFunction up so that it is described by a type. I do not know how to do this without a template.

+2
source

Change This is not a solution. it is more deceiving. But I think he is doing what is needed.

 #define INVOKE(hof, func, arg) \ hof([](const decltype(arg)& arg_){return func(arg_);}, arg) 

Example:

 // This function mimics the signature of QtCollector::run for testing template <typename Functor, typename Arg1> auto QtConcurrent_run(Functor functor, const Arg1 &arg1) -> decltype(functor(arg1)) { return functor(arg1); } #include <iostream> int f(int x) { std::cout << "int" << " " << x << std::endl; return x; } double f(double x) { std::cout << "double" << " " << x << std::endl; return x; } int main() { INVOKE(QtConcurrent_run, f, 3); INVOKE(QtConcurrent_run, f, 3.14); INVOKE(QtConcurrent_run, f, '3'); return 0; } 

Take a look here at ideone.

The original answer follows for historical purposes and some explanation.


Just for clarity, because this is an interesting question, but perhaps more important for you to keep your project moving, there is a reason why you don’t just want to transfer various function overrides to a functor structure and pass the functor structure directly to QtConcurrent :: run who would gladly accept such a thing?

If all function definitions were in the same class, then there would be no problem:

 struct f_collector { ReturnType1 f(ArgType1 arg); ReturnType2 f(ArgType2 arg); ReturnType3 f(ArgType3 arg); // ... // Make it a functor: template<typename Argtype> auto operator()(const Argtype& arg) -> decltype(f(arg)) { return f(arg); } } 

Then you can call QtConcurrent::run(f_collector(), argument) , and it will just work (unless you need a perfect redirect, but this is a trifle).

So I had the following idea, which was to build a functor similar to the above on the fly, which basically means giving it a lambda expression. The lambda itself is quite simple; It's easy enough to make a macro out of it:

 // This is the functor template<typename Arg, typename Func> struct wrapper { wrapper(Func f) : f(f) {} const Func f; auto operator()(Arg arg) const -> decltype(f(arg)) {return f(arg);} }; // As usual, a make_* function, because you can't template deduce a constructor template<typename Arg, typename Func> wrapper<Arg, Func> make_wrapper(Func f) { return wrapper<Arg, Func>(f); } // Boilerplate inside a macro #define INVOKE(hof,func,arg) \ hof(make_wrapper<decltype(arg)>( [](const decltype(arg)& arg_) { \ return func(arg_); \ }), \ arg) // The above was ugly, but it easy to use. For testing, I define // this with a similar signature to QtConcurrent::run template <typename Functor, typename Arg1> auto QtConcurrent_run(Functor functor, const Arg1 &arg1) -> decltype(functor(arg1)) { return functor(arg1); } #include <iostream> int f(int x) { std::cout << "int" << " " << x << std::endl; return x; } double f(double x) { std::cout << "double" << " " << x << std::endl; return x; } int main() { INVOKE(QtConcurrent_run, f, 3); INVOKE(QtConcurrent_run, f, 3.14); INVOKE(QtConcurrent_run, f, '3'); return 0; } 

But then I remembered that lambda, along with its other virtues, can be automatically converted to function pointers if they don't have captures. And this lambda has no captures, because the function itself is the only external symbol, and it is not an object with an automatic storage class. So, I think in the bottom line you can do this with a small template:

 #define INVOKE(hof, func, arg) \ hof([](const decltype(arg)& arg_){return func(arg_);}, arg); 
+1
source

All Articles