如果T的Enumerator只列出了所有元素,那么使用vector是否安全?
答案 0 :(得分:46)
在C ++中不需要它,这就是原因:
C#仅支持动态多态。因此,要创建可重用的算法,您需要一个所有迭代器都将实现的接口。那是IEnumerator<T>
,而IEnumerable<T>
是返回迭代器的工厂。
C ++模板支持鸭子输入。这意味着您不需要通过接口约束泛型类型参数来访问成员 - 编译器将按模板的每个单独实例化的名称查找成员。
C ++容器和迭代器具有隐式接口,相当于.NET IEnumerable<T>
,IEnumerator<T>
,ICollection<T>
,IList<T>
,即:
对于容器:
iterator
和const_iterator
typedefs begin()
会员功能 - 满足IEnumerable<T>::GetEnumerator()
end()
会员功能 - 而不是IEnumerator<T>::MoveNext()
返回值对于前向迭代器:
value_type
typedef operator++
- 而不是IEnumerator<T>::MoveNext()
operator*
和operator->
- 而不是IEnumerator<T>::Current
operator*
的引用返回类型 - 而不是IList<T>
indexer setter operator==
和operator!=
- 在.NET中没有真正的等价物,但容器的end()
匹配IEnumerator<T>::MoveNext()
返回值对于随机访问迭代器:
operator+
,operator-
,operator[]
- 而不是IList<T>
如果您定义了这些,那么标准算法将适用于您的容器和迭代器。不需要任何接口,不需要虚拟功能。不使用虚函数使得C ++通用代码比同等的.NET代码更快,有时候要快得多。
注意:编写通用算法时,最好使用std::begin(container)
和std::end(container)
代替容器成员函数。除了STL容器之外,这允许您的算法与原始数组(没有成员函数)一起使用。原始数组和原始指针满足容器和迭代器的所有其他要求,只有这个例外。
答案 1 :(得分:7)
标准的C ++方法是传递两个迭代器:
template<typename ForwardIterator>
void some_function(ForwardIterator begin, ForwardIterator end)
{
for (; begin != end; ++begin)
{
do_something_with(*begin);
}
}
示例客户端代码:
std::vector<int> vec = {2, 3, 5, 7, 11, 13, 17, 19};
some_function(vec.begin(), vec.end());
std::list<int> lst = {2, 3, 5, 7, 11, 13, 17, 19};
some_function(lst.begin(), lst.end());
int arr[] = {2, 3, 5, 7, 11, 13, 17, 19};
some_function(arr + 0, arr + 8);
Yay泛型编程!
答案 2 :(得分:2)
IEnumerable<T>
在概念上与vector
非常不同。
IEnumerable
提供仅向前,只读对一系列对象的访问权限,无论哪个容器(如果有)容纳对象。 vector
实际上是一个容器本身。
在C ++中,如果要在不提供此容器详细信息的情况下提供对容器的访问,则约定是传入两个表示容器开头和结尾的迭代器。
一个很好的例子是accumulate的C ++ STL定义,可以与IEnumerable<T>.Aggregate对比
在C ++中
int GetProduct(const vector<int>& v)
{
// We don't provide the container, but two iterators
return std::accumulate(v.begin(), v.end(), 1, multiplies<int>());
}
在C#中
int GetProduct(IEnumerable<int> v)
{
v.Aggregate(1, (l, r) => l*r);
}
答案 3 :(得分:2)
据我所知,如果我们严格坚持这个问题,答案就是否定。人们一直在回答C ++中可用的替代品,这可能是很好的信息,但不是答案,而OP最有可能已经知道了。
我完全不同意&#34;它不需要,&#34;只是C ++和.NET标准库的设计是不同的。 IEnumerable&lt;&gt;的主要特征它是多态的,因此它使调用者能够使用他想要的任何类(数组,列表,集等),同时仍然提供编译时强类型,甚至在库API中也是安全的。
C ++中唯一的选择是模板。但是C ++模板不是安全类型的运行时泛型,它们基本上是一种宏。首先,使用C ++中的模板,您必须向需要使用模板的任何人提供整个模板源代码。此外,如果你使你的库API模板化,你将失去保证对它的调用将编译的能力,并且代码不会自动自我记录。
我完全同情任何同时使用C#和C ++的程序员,并对这一点感到沮丧。
然而,C ++ 2X计划添加包括范围(可能满足OP?)的功能;以及概念(解决模板的弱/坏类型检查 - 缺陷admitted by Bjarne Stroustrup本身)和模块(可能有助于减少仅限标题模板的痛苦)。