有没有标准的 C++相当于 IEnumerable在 C# 中?

发布于 2024-12-25 11:50:49 字数 39 浏览 3 评论 0原文

或者,如果 T 的枚举器只是列出所有元素,那么使用向量是否安全?

Or is it safe to use vector if the Enumerator of T is just listing all the elements?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜巴黎 2025-01-01 11:50:49

C++ 中不需要它,原因如下:

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

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

C++ 容器和迭代器具有隐式接口,相当于 .NET IEnumerableIEnumeratorICollection、< code>IList,即:

对于容器:

  • iteratorconst_iterator typedef
  • begin() 成员函数 - 满足 IEnumerable::GetEnumerator()
  • end() 成员函数的需求 - 而不是IEnumerator::MoveNext() 返回值

对于前向迭代器:

  • value_type typedef
  • operator++ -- 而不是IEnumerator::MoveNext()
  • operator*operator-> -- 而不是 IEnumerator:: 来自 operator* 的当前
  • 引用返回类型 - 而不是 IList 索引器设置器
  • operator==operator!= -- 在 .NET 中没有真正的等效项,但容器的 end()IEnumerator::MoveNext() 返回匹配value

对于随机访问迭代器:

  • operator+operator-operator[] - 而不是 IList

如果你定义这些,那么标准算法将适用于您的容器和迭代器。不需要接口,不需要虚拟功能。不使用虚函数使得 C++ 泛型代码比等效的 .NET 代码更快,有时甚至快得多。


注意:在编写通用算法时,最好使用 std::begin(container)std::end(container) 而不是容器成员函数。这允许您的算法除了 STL 容器之外还可以与原始数组(没有成员函数)一起使用。原始数组和原始指针满足容器和迭代器的所有其他要求,但只有一个例外。

It isn't needed in C++, and here's why:

C# only supports dynamic polymorphism. So to create a reusable algorithm, you need an interface which all iterators will implement. That's IEnumerator<T>, and IEnumerable<T> is a factory for returning an iterator.

C++ templates, on the other hand, support duck typing. That means you don't need to constrain a generic type parameter by an interface in order to access members -- the compiler will look up members by name for each individual instantiation of the template.

C++ containers and iterators have implicit interfaces which is equivalent to .NET IEnumerable<T>, IEnumerator<T>, ICollection<T>, IList<T>, namely:

For containers:

  • iterator and const_iterator typedefs
  • begin() member function -- fills the need for IEnumerable<T>::GetEnumerator()
  • end() member function -- instead of IEnumerator<T>::MoveNext() return value

For forward iterators:

  • value_type typedef
  • operator++ -- instead of IEnumerator<T>::MoveNext()
  • operator* and operator-> -- instead of IEnumerator<T>::Current
  • reference return type from operator* -- instead of IList<T> indexer setter
  • operator== and operator!= -- no true equivalent in .NET, but with container's end() matches IEnumerator<T>::MoveNext() return value

For random access iterators:

  • operator+, operator-, operator[] -- instead of IList<T>

If you define these, then standard algorithms will work with your container and iterator. No interface is needed, no virtual functions are needed. Not using virtual functions makes C++ generic code faster than equivalent .NET code, sometimes much faster.


Note: when writing generic algorithms, it's best to use std::begin(container) and std::end(container) instead of the container member functions. That allows your algorithm to be used with raw arrays (which don't have member functions) in addition to the STL containers. Raw arrays and raw pointers satisfy all other requirements of containers and iterators, with this single exception.

苍景流年 2025-01-01 11:50:49

如果我们严格地坚持这个问题,据我所知,答案是否定的。人们一直在回复 C++ 中可用的替代品是什么,这可能是很好的信息,但不是答案,而且 OP 很可能已经知道了。

我完全不同意“不需要”,只是C++和.NET标准库的设计不同。 IEnumerable<>的主要特点是它是多态的,因此它使调用者能够使用他想要的任何类(数组、列表、集合等),同时仍然提供编译时强类型,即使在库 API 中也能实现故障安全。

C++ 中唯一的替代方案是模板。但 C++ 模板不是安全类型的运行时泛型,它们基本上是一种宏。因此,首先使用 C++ 中的模板,您必须向需要使用您的模板的任何人提供整个模板源代码。此外,如果您将库 API 模板化,您将无法保证对它的调用能够编译,并且代码不会自动自记录。

我完全同情任何其他同时使用 C# 和 C++ 的程序员,并对这一点感到沮丧。

然而,C++2X 计划添加包括范围在内的功能(这可能满足 OP?);以及概念(解决了模板的弱/坏类型检查问题 - Bjarne Stroustrup 承认的缺陷 他自己)和模块(这可能会或可能不会帮助减少仅标题模板的痛苦)。

If we stick to the question strictly the answer is no, as far as I know. People have kept replying what is the substitute available in C++, which may be good info but not answers, and which the OP most probably knew already.

I completely disagree that "it is not needed," it is just that the designs of the C++ and .NET standard libraries are different. The main feature of IEnumerable<> is that it's polymorphic, and so it enables the caller to use whatever class he wants (array, List, Set etc.), while still providing compile-time strong typing, fail-safe even in library APIs.

The only alternative in C++ is templates. But C++ templates are not safely typed run-time generics, they are basically kind of macros. So first of all with templates in C++ you are forced to provide the whole template source code to whoever needs to use your template. Moreover if you make your library API templated you lose the ability to guarantee that a call to it will compile, and the code is not automatically self-documenting.

I fully sympathize with any other programmer who uses both C# and C++ and is frustrated with this point.

However C++2X is planned to add features including ranges (which may satisfy the OP?); as well as concepts (which address the weak/bad type-checking of templates -- flaw admitted by Bjarne Stroustrup himself), and modules (which may or may not help reducing the pain from header-only templates).

活泼老夫 2025-01-01 11:50:49

标准 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);

通用编程!

The standard C++ way is to pass two iterators:

template<typename ForwardIterator>
void some_function(ForwardIterator begin, ForwardIterator end)
{
    for (; begin != end; ++begin)
    {
        do_something_with(*begin);
    }
}

Example client code:

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 generic programming!

最近可好 2025-01-01 11:50:49

IEnumerable 在概念上与 vector 非常不同。

IEnumerable 提供对对象序列的只进只读访问,无论什么容器(如果有)保存对象。 向量实际上是一个容器本身。

在 C++ 中,如果您想要提供对容器的访问而不提供该容器的详细信息,则约定是传入两个代表容器开始和结束的迭代器。

一个很好的例子是 accumulate 的 C++ STL 定义,它可以与 < a href="http://msdn.microsoft.com/en-us/library/bb548651.aspx" rel="noreferrer">IEnumerable.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);
  }

IEnumerable<T> is conceptually very different from vector.

The IEnumerable provides forward-only, read-only access to a sequence of objects, regardless of what container (if any) holds the objects. A vector is actually a container itself.

In C++, should you want to provide access to a container without giving the details of this container, the convention is to pass in two iterators representing the beginning and end of the container.

A good example is the C++ STL definition of accumulate, which can be contrasted with IEnumerable<T>.Aggregate

In 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>());
   }

In C#

  int GetProduct(IEnumerable<int> v)
  {
        v.Aggregate(1, (l, r) => l*r);
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文