如何获取指向编译器选择的重载函数的函数指针
How to get a function pointer to the overloaded function that the compiler chooses?
如何获取指向编译器在检查参数后选择的重载函数的函数指针?在本例中:
#include <iostream>
void MyFunction(float a){}
void MyFunction(int a){}
int main()
{
float a;
MyFunction(a);
void (*manualFunctionPointer)(float);
manualFunctionPointer(a);
// automaticFunctionPointer = ?
}
我已经指定了我想要一个函数指针,指向接受float并返回void的函数。编译器当然可以自己解决这个问题,因为MyFunction(a)调用调用的是正确的函数。有没有一种方法可以让函数指针指向编译器选择的函数?
#include <iostream>
void MyFunction(float a){std::cout << "floatn";}
void MyFunction(int a){std::cout << "intn";}
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);
}
以上工作。我用4种不同的方式选择了MyFunction。
如果你愿意做一些样板工作,并想解决"如果a是char
怎么办"的问题,那么这可能会有所帮助:
// 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);
}
但是,如前所述,这需要我们将MyFunction
封装起来,以便用类型来描述它。我不知道有什么方法可以在没有样板的情况下做到这一点。
编辑:这不是真正的解决方案;这更像是一个骗局。但我认为它做到了需要的。
#define INVOKE(hof, func, arg)
hof([](const decltype(arg)& arg_){return func(arg_);}, arg)
示例:
// 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;
}
在这里看ideone。
出于历史目的和一点解释,以下是最初的答案。
为了清楚起见,因为这是一个有趣的问题,但也许对你来说,推动你的项目更重要,你有没有理由不想把各种函数重写封装到一个函子结构中,并将函子结构直接传递给QtConcurrent::run,它会很乐意接受这样的事情?
如果函数的所有定义都在一个类中,那么就没有问题了:
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); }
}
然后,您可以调用QtConcurrent::run(f_collector(), argument)
,它就会正常工作(除非您需要完美的转发,但这只是一个小细节)。
所以我有了以下想法,那就是在运行中构建一个像上面这样的函子,这基本上意味着给它一个lambda表达式。lambda本身很容易成为样板;很容易用它制作一个宏:
// 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's 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;
}
但后来我想起了lambda及其其他优点,只要它们没有捕获,就可以自动转换为函数指针。这个lambda没有捕获,因为唯一的外部符号是函数本身,而它不是具有自动存储类的对象。所以,我认为底线是,你实际上可以用一点样板来做到这一点:
#define INVOKE(hof, func, arg)
hof([](const decltype(arg)& arg_){return func(arg_);}, arg);
替换中的浮点
void (*manualFunctionPointer)(float);
带
void (*manualFunctionPointer)(decltype(a));
然后,无论a发生什么变化,manualFunctionPointer都将跟随
- QMetaObject invokeMethod的基于函数指针的语法
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- c++r值引用应用于函数指针
- 模板函数指针和lambda
- 是否可以将llvm::FunctionType转换为C/C++原始函数指针
- 带有类的函数指针
- () 函子后面的括号,而不是函数指针?
- 全局作用域中函数指针的赋值
- 使用"Task"函数指针队列定义作业管理器
- 将成员函数指针作为参数传递给模板方法
- 如何创建对象函数指针C++映射?
- 匹配函数指针作为模板参数?
- 通过函数指针定义类范围之外的方法
- 存储在类中的函数指针
- C++从函数指针数组调用函数
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 整数键映射到头文件中的成员函数指针
- 从类成员函数到类 C 函数指针的转换
- 如何将内联匿名函数分配给C++函数指针
- 将字符缓冲区强制转换为函数指针