または、Tの列挙子が単にすべての要素をリストしている場合は、ベクトルを使用しても安全ですか?
C++では必要ありません。その理由は次のとおりです。
C#は動的ポリモーフィズムのみをサポートします。したがって、再利用可能なアルゴリズムを作成するには、すべての反復子が実装するインターフェースが必要です。それが_IEnumerator<T>
_であり、_IEnumerable<T>
_はイテレータを返すためのファクトリです。
一方、C++テンプレートはダックタイピングをサポートしています。つまり、メンバーにアクセスするためにインターフェイスでジェネリック型パラメーターを制約する必要はありません。コンパイラーは、テンプレートの個々のインスタンス化ごとにメンバーを名前で検索します。
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コンテナーに加えて、生の配列(メンバー関数を持たない)でアルゴリズムを使用できます。生の配列と生のポインタは、この1つの例外を除いて、コンテナとイテレータの他のすべての要件を満たします。
標準のC++の方法は、2つの反復子を渡すことです。
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);
やったジェネリックプログラミング!
私たちが質問に厳密に固執する場合、私の知る限り、答えはノーです。人々はC++で利用できる代替物は何であるかについて返答し続けました。これは良い情報ではあるかもしれませんが、回答ではなく、OPがおそらくすでに知っていました。
「必要ない」というのはまったく同意できません。C++と.NETの標準ライブラリのデザインが異なるだけです。 IEnumerable <>の主な機能は多態性であるため、呼び出し元が必要なクラス(配列、リスト、セットなど)を使用しながら、ライブラリAPIでもコンパイル時の強力な型指定、フェイルセーフを提供できます。 。
C++での唯一の代替手段はテンプレートです。しかし、C++テンプレートは安全に型指定されたランタイムジェネリックではなく、基本的にマクロの一種です。したがって、まずC++のテンプレートを使用すると、テンプレートを使用する必要のあるユーザーにテンプレートのソースコード全体を提供する必要があります。さらに、ライブラリAPIをテンプレート化すると、その呼び出しがコンパイルされることを保証できなくなり、コードは自動的に自己文書化されません。
私は、C#とC++の両方を使用していて、この点に不満を持っている他のプログラマーに完全に同情しています。
ただし、C++ 2Xは範囲(OPを満たす可能性があるか?)を含む機能を追加する予定です。また、概念(テンプレートの弱い/悪い型チェックに対処する-欠陥 Bjarne Stroustrupによって承認された 自身)、およびモジュール(ヘッダーのみのテンプレートの痛みを軽減するのに役立つ場合とそうでない場合がある) )。
IEnumerable<T>
はvector
と概念的に非常に異なります。
IEnumerable
はforward-only、read-onlyオブジェクトを保持するコンテナ(存在する場合)に関係なく、オブジェクトのシーケンスへのアクセス。 vector
は実際にはコンテナそのものです。
C++では、このコンテナーの詳細を指定せずにコンテナーへのアクセスを提供する場合、規則は、コンテナーの開始と終了を表す2つの反復子を渡すことです。
良い例が 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);
}