我可以创建一个接受函数和函子作为参数的谓词吗?

Bil*_*rey 3 c++ templates

我正在研究C++中的一个问题,它涉及大量数据的大量子集和转换操作.为此,我创建了一个map函数和list comprehensions之类的东西.我发现我写的一堆谓词也有反转,所以我需要写:

template <typename type_t>
bool HasTenFoo(const type_t &t) {
  return t.foo >= 10.0;
}
Run Code Online (Sandbox Code Playgroud)

template <typename type_t>
bool DoesntHaveTenFoo(const type_t &t) {
  return t.foo < 10.0;
}
Run Code Online (Sandbox Code Playgroud)

这些都不是一个真实的例子,但它们具有代表性.我也使用了相当数量的仿函数:

class HasEnoughFoo {
public:
  HasEnoughFoo (double bar) { this->bar = bar; }
  template<typename type_t>
  bool operator()(const type_t &t) const { return t.foo >= bar; }
private:
  double bar;
};
Run Code Online (Sandbox Code Playgroud)

其中一些也应该反转.我不想不必要地重复代码,而是编写一个将谓词作为参数并将返回该谓词的(反转值)的仿函数.我的拳头切成一个在下面:

/* -- Returns the opposite of some other predicate -------------------------- */

template<typename predicate_t>
class Not {
public:
  template <typename predicate_t>
  Not(predicate_t *p) { predicate = p; }

  template <typename type_t>
  bool operator()(const type_t &t) const {
    return !(*predicate)(t);
  }

private:
  predicate_t *predicate;
};
Run Code Online (Sandbox Code Playgroud)

我会用以下的东西来称呼它:

new_list = old_list.subset(Not<HasEnoughFoo>(&HasEnoughFoo(10.0));
Run Code Online (Sandbox Code Playgroud)

要么

new_list = old_list.subset(Not<HasTenFoo>(&HasTenFoo));
Run Code Online (Sandbox Code Playgroud)

这似乎predicate_t是一个类似的函子HasEnoughFoo,但是在predicate_t引用常规函数时失败了HasTenFoo.

Visual Studio抱怨说'HasTenFoo' is not a valid template type argument for parameter 'predicate_t'.有没有办法编写一个可以与函子和函数一起使用的Not()谓词,或者我注定要编写几十个谓词及其反转?

Unc*_*ens 5

这是你的代码工作的一个例子(我删除了foo成员,所以它只适用于双打).

template <typename type_t>
bool HasTenFoo(const type_t &t) {
  return t >= 10.0;
}

class HasEnoughFoo {
public:
  HasEnoughFoo (double bar) { this->bar = bar; }
  template<typename type_t>
  bool operator()(const type_t &t) const { return t >= bar; }
private:
  double bar;
};


template<typename predicate_t>
class Not {
public:
  Not(predicate_t p): predicate(p) { }

  template <typename type_t>
  bool operator()(const type_t &t) const {
    return !predicate(t);
  }

private:
  predicate_t predicate;
};

template <class predicate_type>
Not<predicate_type> Negate(predicate_type p)
{
    return p;
}

#include <iostream>
int main()
{
    std::cout << Negate(HasTenFoo<double>)(11.0) << '\n';
    std::cout << Negate(HasEnoughFoo(13.0))(11.0) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

一些重要的说明:

Not的构造函数使用初始化列表.这消除了谓词类型具有默认构造函数(HasEnoughFoo没有)的要求.

你肯定不想搞乱指向谓词的指针.功能对象应该是轻量级的对象,可以无需担心地复制.

由于并非是一个模板类,有可能引起复杂的模板参数,但你通常只是用它作为临时(不具名参数取谓词的函数),添加推导出复杂的类型,你的模板函数(在整个标准库中使用的技巧) - 这里Negate.