1

我有一个声明如下的函数;它的确切工作与此无关。

template<typename T>
std::pair<int, int>
partition3(T *pT, const int N, const T &Kq, const int w,
           std::function<int(const T&, const T&, int)> P);

在呼叫站点,我尝试执行以下操作:

bool partition3_test()
{
  struct cmp
  {
    int operator()(int x, int y, int) const
    { return x-y; }
  };

  int V1[11] = { 3, 7, 1, 7, 7, 8, 10, 2, 16, 4, 3 },
      V2[11] = { 3, 6, 1, 6, 6, 8, 10, 2, 16, 4, 3 };

  std::function<int(const int&, const int&, int)> F = cmp();

  std::pair<int, int>
    p1  = partition3(V1, 11, 7, 0, cmp()),
    p2  = partition3(V2, 11, 7, 0, cmp());

  return false;
}

对于partition3编译器的两次调用(MSVC 2010)抱怨它无法推断出最后一个参数的模板参数。如果我替换cmp()F,则代码可以编译并正常工作。

我有两个问题:

  1. 为什么我会收到错误消息?[编译器错误或一些神秘的 C++ 规则?]
  2. 如果不首先明确构造,我怎样才能达到相同的效果F

(目前,我已经通过引入另一个模板参数partition3并声明P为该模板类型来解决该问题。)

4

1 回答 1

4

cmp()实际上根本不是std::function。复制初始化工作的事实可能会使问题感到困惑,但是它使用了一个必须使用某种包装器对象的转换构造函数,我很惊讶它对一个临时仿函数对象起作用(啊,检查它的标准显然制作仿函数的副本)。

最重要的是,函数参数不匹配(按值传递和按常量传递是源兼容的,但不是运行时调用兼容的),这又需要一个适配器。

最好的解决方案是使模板函数更通用,这样它也可以与原始函数指针和任意仿函数对象一起使用,而不仅仅是std::function

template<typename T, typename Functor>
std::pair<int, int> partition3(T *pT, const int N, const T &Kq, const int w,
                               const Functor& P);

如果出于某种原因您真的想使用std::function(例如,您需要虚拟调度),您可以。与 Nawaz 写的完全相反的错误是,这一个可推导的上下文,但不止一种类型适合(这是适配器/包装器性质std::function变得重要的地方,因为类型不必与参数完全匹配,它只需要兼容。 std::function<int(const long&, const long&, int)>也会匹配。)

改为使用不可推导的上下文,这样编译器甚至不会尝试使用仿函数来推导T.

template<typename T, typename Functor>
std::pair<int, int> partition3(T *pT, const int N, const T &Kq, const int w,
                               std::function<std::identity<const T>::type&, std::identity<const T>::type&, int> P);
于 2012-04-15T13:34:37.367 回答