8

我有一个std::vector指针Person对象,它有一个成员函数std::string getName() const。使用 STL 算法,我想计算Person向量中getName()返回“Chad”的所有对象。

简单地迭代循环的行为将是:

int num_chads = 0;
for(std::vector<Person *>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
    if((*it)->getName() == "Chad")
        ++num_chads;
}

我想重新设计它,以便它使用所有 STL 算法和仿函数等(使其更加面向功能)。这是我认为我需要做的:

const int num_chads = std::count_if(vec.begin(), vec.end(),
                                    std::bind1st(std::bind2nd(std::equal_to, mem_fun(Person::getName)), "Chad"));

正如您可能会说的那样,这是行不通的。首先,据我了解,您不能在 binder1st/binder2nd 对象上使用 bind1st/bind2nd,因为它们是专门为使用std::binary_functions. 其次,更重要的是,我认为我没有使用正确的技术。我确实想将其中一个参数绑定到“Chad”,但是对于迭代器参数,我实际上只想在调用绑定版本之前将迭代器值转换为字符串equals_to

我认为使用 Boost 可以做到这一点,但是否可以只使用核心 C++03(即没有 C++0x 羔羊!)?

编辑:谁能想出一个不使用用户定义谓词的示例(即仅使用 std 工具包中提供的工具)?

编辑:虽然 Matthieu 的答案是关于如何在 STL 算法中使用函子的教科书答案,但 Cubbi 的答案来自我正在寻找的方法(尽管在我编辑问题以使其更具体之前,Mathieu 确实回答了,所以在这里道歉!)。

4

3 回答 3

9

我一直发现 lambdas 相对不可读。我更喜欢编写显式类型:

struct Named
{
  Named(char const* ref): _ref(ref) {}
  bool operator()(Person* p) const { return p && p->getName() == _ref; }
  char const* _ref;
};

size_t const c = std::count_if(vec.begin(), vec.end(), Named("Chad"));

尽管 的定义Named是“外线”,但正确选择的名称传达了意图并隐藏了实现细节。就个人而言,我认为这是一件好事,因为这样我就不会因为实现细节而分心,也不会试图通过对代码进行逆向工程来弄清楚发生了什么(尽管它可能很明显)。

于 2011-03-16T13:24:24.650 回答
5

由于还没有人发布实际的 boost 代码,所以 C++98 和 boost:

ptrdiff_t num_chads = std::count_if(vec.begin(), vec.end(),
                      boost::bind(&Person::getName, _1) == "Chad");

试运行https://ideone.com/PaVJe

至于纯 C++,我认为没有compose1适配器是不可能的,它存在于 STL 但不在 C++ stdlib 中......

这里是(使用 GCC 的 STL 实现)

ptrdiff_t num_chads = std::count_if(vec.begin(), vec.end(),
                     __gnu_cxx::compose1(
                         std::bind2nd(std::equal_to<std::string>(), "Chad"),
                         std::mem_fun(&Person::getName)));

测试运行:https ://ideone.com/EqBS5

编辑:更正以说明Person*

于 2011-03-16T14:29:02.720 回答
1

使用boost::bind,它在某种程度上优于现有的标准绑定机制。boost::bind完全兼容 C++03。

于 2011-03-16T13:36:36.520 回答