我有一类兴趣(称之为X)。
我有一个std::list (称为L)。
我有一个函数(称为F)。

F(L)根据检查列表中每个X的内部状态的算法返回L的子集(std::list )。

我在我的应用程序中添加了一个std::map (称为M),并且我需要定义F(M)以便以与F(L)相同的方式进行操作-也就是说, F(M)还必须返回std::list ,这是通过检查映射中每个X的内部状态确定的。

作为一个自描述为懒惰的程序员,我立即看到算法在逻辑上将是相同的,并且每种数据类型(std::list和std::map)都是可迭代的模板。我不想重复维护相同的算法,但是我不确定如何继续前进。

一种方法是从F(M)中获取X *(即键值映射中的“值”),将其放入std::list 中,然后在到F(std::list ),传递返回的std::list ;回来。我看不到这是唯一的方法。

我的问题:如何将核心算法保留在一个位置,但保留对序列或对关联容器的值进行迭代的能力?

谢谢!

最佳答案

首先,除了两个条件外,其他所有条件都可以使用std::remove_copy_if完成。尽管名称为remove_copy_if,但它不会从原始集合中删除任何内容。我认为,如果将其称为filtered_copy,人们会更容易理解。它将元素从一个集合复制到另一个。对于每个元素,它调用一个谓词,并且仅当谓词对该元素返回false时,该项目才会被复制。

剩下的只有一个责任:实现测试功能,该功能可以查看每个X *,并说明是否应将其排除在您制作的拷贝之外。由于您要使用两种不同的方法来应用一种逻辑,因此我将逻辑封装在一个类的私有(private)函数中。然后可以通过两种方式将它作为类的operator()的重载版本提供给外界:

class F {
    bool do_test(X const *x) const { return x.internal_stuff; }
public:
    bool operator()(X const *x) const { return do_test(x); }

    bool operator()(std::pair<int, X const *> const &p) const {
        return do_test(p.second);
    }
};

由于operator()(X const *)是对do_test()的纯粹追求,您可能想要摆脱它,但是IMO可能弊大于利。

无论如何,这将您的逻辑完全放在一个地方(F::do_test)。它还提供了一种简单一致的语法,用于创建list<X *>std::map<int, X *>的过滤拷贝:
std::list<X *> result;
std::remove_copy_if(coll.begin(), coll.end(), std:back_inserter(result), F());

最后一点:std::list可能是现有的使用最多的集合。尽管确实有其用途,但它们确实很少见。 std::vectorstd::deque通常更好。

07-27 19:42