如何获取编译器选择的重载函数的函数指针?

时间:2012-11-29 18:41:16

标签: c++ c++11

如何在检查参数后获取编译器将选择的重载函数的函数指针?在这个例子中:

#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)调用调用了正确的函数。有没有办法获得编译器选择的函数的函数指针?

3 个答案:

答案 0 :(得分:2)

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

以上作品。我以4种不同的方式选择了MyFunction。

如果你愿意做一些事情,并想要解决&#34;如果a是char&#34;问题,那么这可能会有所帮助:

// 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包起来,以便按类型进行描述。如果没有样板,我不知道如何做到这一点。

答案 1 :(得分:1)

修改:这不是真正的解决方案;这更像是一个骗子。但我认为它可以满足需要。

#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上查看here

原始答案如下,出于历史目的和一些解释。


为了清楚起见,因为这是一个有趣的问题,但也许让你的项目移动更重要,有没有理由你不想将各种函数覆盖包装到functor结构中,并且将functor结构直接传递给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);

答案 2 :(得分:0)

替换

中的浮动
void (*manualFunctionPointer)(float);

使用

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

然后无论发生什么变化,manualFunctionPointer都会跟随