C#中有IEnumerable <t>的标准C ++等价物吗?</t>

时间:2012-01-06 21:17:21

标签: c# c++ ienumerable

如果T的Enumerator只列出了所有元素,那么使用vector是否安全?

4 个答案:

答案 0 :(得分:46)

在C ++中不需要它,这就是原因:

C#仅支持动态多态。因此,要创建可重用的算法,您需要一个所有迭代器都将实现的接口。那是IEnumerator<T>,而IEnumerable<T>是返回迭代器的工厂。

另一方面,

C ++模板支持鸭子输入。这意味着您不需要通过接口约束泛型类型参数来访问成员 - 编译器将按模板的每个单独实例化的名称查找成员。

C ++容器和迭代器具有隐式接口,相当于.NET IEnumerable<T>IEnumerator<T>ICollection<T>IList<T>,即:

对于容器:

  • iteratorconst_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本身)和模块(可能有助于减少仅限标题模板的痛苦)。