我试图通过实现类似于C#的Linq来熟悉C ++中的模板。最后,查询数据看起来应该是这样的
SomeIteratorType begin = /* ... */;
SomeIteratorType end = /* ... */;
typedef iterator_traits<SomeIteratorType>::value_type Type;
linq<int> query = linq<Type>(begin, end)
.where([](Type value) -> bool { return /* ... */; })
.select([](Type value) -> int { return value.some_property; });
for (int value : query)
cout << value << endl;
我从
开始template<typename Type>
class linq : public std::iterator<std::input_iterator_tag, Type> {
public:
typedef bool (WherePredicate)(Type value);
// ...
// Copy-constructor, operator=, operator++, ...
// ...
// ...
// Linq functions, e.g.
linq& where (WherePredicate& predicate) const; // returns some specialization of the linq-class (should probably not name this "where")
// ...
};
但是如何从示例中声明构造函数linq(begin, end)
?如果begin
和end
属于IteratorType
类型,我需要生成的linq
对象属于linq<std::iterator_traits<IteratorType>::value_type>
类型。甚至可以从函数模板参数中计算出类模板参数吗?如果没有,是否至少可以确保IteratorType begin
和IteratorType end
足够std::iterator_traits<IteratorType>::value_type == Type
,就像linq<Type>(begin, end)
一样使用?
答案 0 :(得分:0)
因此C#使用堆分配的对象和间接通过接口,就好像它是免费的一样。
如果你想模仿它,你必须这样做。如果你也想要值语义,你必须编写包含智能指针的包装器,并且表现得像值。
另一种方法是不输入擦除;相反,linq对象是每个修饰符链的唯一类型。这里linq
是一个函数而不是tyoe,并且您将返回值存储在auto
个变量中。
这两种方法可以一起工作,比如lambda(没有类型ersaure callables)和std函数(可以在构造时堆积分配和类型擦除的值类型,以便忘记除callable之外的所有调用接口)。
为了更进一步,了解类型擦除(包括如何编写std函数),使用C ++中的常规类型,并且可以在Rangesv3中查找一个支持类似linq的流表达式的库。