我正在尝试为我的基类 Iterator 编写 LINQ 样式的方法,List 和 Sequence 将从中继承,但是这两个容器将有自己的这些方法的实现。 “Where”方法非常简单。 “选择”方法非常棘手;你不能有虚拟模板方法。
template <typename T>
class Iterator {
public:
virtual ~Iterator() {};
// This is illegal, but if it weren't, it would be the functionality I want.
template <typename R>
virtual shared_ptr<IIterator<R>> Select(const function<R(T)>& func) = 0;
virtual shared_ptr<IIterator<T>> Where(const function<bool(T)>& func) = 0;
};
例如,“选择”将允许您将“火腿三明治”类型的迭代器转换为“生菜”类型的迭代器。
HamSandwiches->Select<'Lettuce'>([] (shared_ptr<'HamSandwich'> hs) { return hs->Lettuce; });
忽略单引号。
既然我们不能有虚模板函数,我当然不能把函数做成虚函数。在那种情况下,我们有一个普通的旧函数,与虚函数相比,我们永远不应该通过在 List 和 Sequence 中编写实现来“隐藏”它的实现;这将被视为设计缺陷。
template <typename T>
class Iterator {
public:
virtual ~Iterator() {};
template <typename R>
shared_ptr<Iterator<R>> Select(const function<R(T)>& func);
virtual shared_ptr<Iterator<T>> Where(const function<bool(T)>& func) = 0;
};
template <typename T>
template <typename R>
shared_ptr<Iterator<R>> Iterator<T>::Select(const function<R(T)>& func) {
//Implementation - What would it be?
}
现在我们必须在我们的基类中实现,这个实现需要在某种程度上特定于 List 和 Sequence。据我所知,您将开始创建 protected “实现函数”以在“选择”中执行某些可能被列表或序列覆盖的操作。
我不是在这里寻找确切的答案,我正在寻找可以帮助我到达我可能/应该去的地方的东西。有没有人发现任何常见的问题或我一开始可能做错的事情?
最佳答案
选项1
我所看到的在 C++ 中实现 LINQ 的想法根本不依赖于虚拟方法。相反,每个结果都包装在一个模板类中返回,大致如下所示:
template <class T>
class RangeWrapper
{
public:
template <class U>
Select(U u) -> decltype(...) {
return RangeWrapper<SelectRange, U>(_myRange, u);
}
private:
T& _myRange;
};
如果您链接其中的几个,返回类型可能会变得相当大,但这是在编译时完成所有工作所付出的代价。
选项 2
您可以实现类型删除以始终返回 Iterator<T>
类型的迭代器.这应该很容易在网络上使用类型删除的迭代器库来实现(有很多,你可以看看 boost.TypeErasure ,它已被接受但尚未发布)。
或者,您可以在 boost 中使用 any_range,如果您可以使用范围(它们比迭代器更自然地映射到 LINQ)。
选项3
如果您不将此作为培训练习,那么已经实现了多种解决方案。使用谷歌。值得注意的是,Microsoft itself is working on a C++ Linq to implement the reactive extensions on top of it .
关于c++ - 编写 C++11 LINQ 风格的 Select,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13445582/