我有一类兴趣(称之为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::vector
和std::deque
通常更好。