在这种情况下,为什么c ++模板参数推断失败?

rsp*_*984 4 c++ templates delegates boost function-pointers

我正在尝试编写自己的委托系统作为boost :: functions的替代,因为后者执行了大量的堆分配,我认为这些分配是有问题的.
我已将此作为替换(简化,实际使用池内存和放置新的但这很简单,可以重现错误):

template<class A, class B>
struct DelegateFunctor : public MyFunctor {
  DelegateFunctor(void (*fptr)(A, B), A arg1, B arg2) : fp(fptr), a1(arg1), a2(arg2) {}

  virtual void operator()() { fp(a1, a2); }

  void (*fp)(A, B);  // Stores the function pointer.
  const A a1; const B a2;  // Stores the arguments.
};
Run Code Online (Sandbox Code Playgroud)

和这个辅助函数:

template<class A, class B>
MyFunctor* makeFunctor(void (*f)(A,B), A arg1, B arg2) {
  return new DelegateFunctor<A,B>(f, arg1, arg2);
}
Run Code Online (Sandbox Code Playgroud)

奇怪的事情发生在这里:

void bar1(int a, int b) {
  // do something
}

void bar2(int& a, const int& b) {
  // do domething
}

int main() {
  int a = 0;
  int b = 1;

  // A: Desired syntax and compiles.
  MyFunctor* df1 = makeFunctor(&bar1, 1, 2);

  // B: Desired syntax but does not compile:
  MyFunctor* df2 = makeFunctor(&bar2, a, b);

  // C: Not even this:
  MyFunctor* df3 = makeFunctor(&bar2, (int&)a, (const int&)b);

  // D: Compiles but I have to specify the whole damn thing:
  MyFunctor* df4 = makeFunctor<int&, const int&>(&bar2, a, b);
}
Run Code Online (Sandbox Code Playgroud)

我为版本C获得的编译器错误(B类似)是:

error: no matching function for call to ‘makeFunctor(void (*)(int&, const int&), int&, const int&)’
Run Code Online (Sandbox Code Playgroud)

这很奇怪,因为编译器在其错误消息中实际上已正确地推断出类型.

有什么方法可以让B版进行编译吗?boost :: bind如何解决这个限制?
我正在使用GCC 4.2.1.请不要使用C++ 11解决方案.

Ker*_* SB 5

论证扣除剥离了参考文献.通过匹配函数指针签名A,我们想得到int &,但通过匹配实际参数,我们想要int,因此扣除失败.

一种解决方案是使第二种类型不推导,如下所示:

#include <type_traits>

template <typename R, typename A, typename B>
R do_it(R (*func)(A, B),
        typename std::common_type<A>::type a,   // not deduced
        typename std::common_type<B>::type b)   // not deduced
{
    return func(a, b);
}
Run Code Online (Sandbox Code Playgroud)

现在A,B完全由函数指针的签名决定:

int foo(int &, int const &);

int main()
{
    int a = 0, b = 0;
    return do_it(foo, a, b);  // deduces A = int &, B = int const &
}
Run Code Online (Sandbox Code Playgroud)

(注意,这std::common_type<T>::type是"身份类型"的推荐习惯用法,其唯一目的是从参数推断中删除模板参数.这之前被称为identity<T>::typeor之类的东西alias<T>,但是标准库特性std::common_type就可以很好地服务于此目的.)