Ben*_*igt 48
在C++中不需要它,这就是为什么:
C#仅支持动态多态.因此,要创建可重用的算法,您需要一个所有迭代器都将实现的接口.那是IEnumerator<T>
,并且IEnumerable<T>
是一个返回迭代器的工厂.
另一方面,C++模板支持duck typing.这意味着您不需要通过接口约束泛型类型参数来访问成员 - 编译器将按名称查找模板的每个单独实例化的成员.
C++的容器和迭代器具有隐式接口这相当于.NET IEnumerable<T>
,IEnumerator<T>
,ICollection<T>
,IList<T>
,即:
对于容器:
iterator
和const_iterator
typedefsbegin()
成员函数 - 满足需要 IEnumerable<T>::GetEnumerator()
end()
成员函数 - 而不是IEnumerator<T>::MoveNext()
返回值对于前向迭代器:
value_type
的typedefoperator++
- 代替 IEnumerator<T>::MoveNext()
operator*
和operator->
-而不是IEnumerator<T>::Current
operator*
- 而不是IList<T>
索引器设置器operator==
并且operator!=
- 在.NET中没有真正的等价物,但是容器的end()
匹配IEnumerator<T>::MoveNext()
返回值对于随机访问迭代器:
operator+
,operator-
,operator[]
-而不是IList<T>
如果您定义了这些,那么标准算法将适用于您的容器和迭代器.不需要任何接口,不需要虚拟功能.不使用虚函数使得C++通用代码比等效的.NET代码更快,有时候要快得多.
注意:编写通用算法时,最好使用std::begin(container)
而std::end(container)
不是容器成员函数.除了STL容器之外,这允许您的算法与原始数组(没有成员函数)一起使用.原始数组和原始指针满足容器和迭代器的所有其他要求,只有这个例外.
标准的C++方法是传递两个迭代器:
template<typename ForwardIterator>
void some_function(ForwardIterator begin, ForwardIterator end)
{
for (; begin != end; ++begin)
{
do_something_with(*begin);
}
}
Run Code Online (Sandbox Code Playgroud)
示例客户端代码:
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);
Run Code Online (Sandbox Code Playgroud)
Yay泛型编程!
据我所知,如果我们严格地坚持这个问题,答案是否定的。人们一直在回答 C++ 中可用的替代品是什么,这可能是很好的信息,但不是答案,而且 OP 很可能已经知道了。
我完全不同意“不需要”,只是 C++ 和 .NET 标准库的设计不同。IEnumerable<> 的主要特点是它是多态的,因此它使调用者能够使用他想要的任何类(数组、列表、集合等),同时仍然提供编译时强类型,即使在库 API 中也是安全的.
C++ 中唯一的选择是模板。但是 C++ 模板不是安全类型化的运行时泛型,它们基本上是一种宏。因此,首先对于 C++ 中的模板,您必须将整个模板源代码提供给需要使用您的模板的任何人。此外,如果您使库 API 模板化,您将无法保证对它的调用将被编译,并且代码不会自动自我记录。
我完全同情任何其他同时使用 C# 和 C++ 并且对这一点感到沮丧的程序员。
然而,C++2X 计划添加包括范围在内的功能(这可能满足 OP?);以及概念(解决模板的弱/错误类型检查——Bjarne Stroustrup本人承认的缺陷)和模块(这可能有助于也可能无助于减轻仅标头模板的痛苦)。
IEnumerable<T>
在概念上与vector
.
该IEnumerable
规定只进,只读到对象的序列访问,无论何种容器(如果有的话)持有的对象。Avector
实际上是一个容器本身。
在 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>());
}
Run Code Online (Sandbox Code Playgroud)
在 C# 中
int GetProduct(IEnumerable<int> v)
{
v.Aggregate(1, (l, r) => l*r);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
15164 次 |
最近记录: |