web-dev-qa-db-ja.com

テンプレート関数:イテレータを渡す

次の設定でデザインを選択するのに苦労しています。

(C++)関数を作成して(テンプレートコンテナーへの)反復子のペアを取り、反復子が指しているのと同じ型の戻り値を計算しています。

Sum関数を実装したいとしましょう(これはポイントを説明するための単なる例です)。

私の見方では、2つのオプションがあり、どちらにも欠点があります。

オプション1

コンテナーが格納するタイプを定義する関数テンプレートパラメーターTを作成します。

パラメータは1つだけ必要ですが、MyContainerのイテレータでのみ関数を使用できます。

template <class T>
T sum(typename MyContainer<T>::IteratorRange range){

    T sum;
    for (auto it = range.first; it < range.second; ++it) {
        sum += *it;
    }
    return sum;
}

オプション2

関数が任意のIteratorRangeテンプレートクラスと2番目のクラスUを受け取り、戻り値の型を決定します。

イテレーターは任意のコンテナーから取得できますが、戻り値の型は常にイテレーターが指すものと同じ型ですが、2つのテンプレートクラスが必要です。

template <class IteratorRange, class U>
U sum(IteratorRange range){

    U sum;
    for (auto it = range.first; it < range.second; ++it) {
        sum += *it;
    }
    return sum;
}

どのオプションがよりクリーンであるか、または両方のオプションの利点を提供する代替手段はありますか?

ボーナス質問

sum変数をどのように初期化する必要がありますか?

5
1v0

反復する範囲

C++標準ライブラリは、ここでは標準的な形式を提供します accumulate ;

template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );

最初から最後まで(最後を除く)の範囲を取り、範囲内の各要素をinit値に初期値として追加します。また、戻り値の型を初期型から推測します。

sumの実装が必要な場合は、accumulateをそのまま使用することをお勧めします。適切でない場合、範囲[first、last)を取る関数シグネチャは、標準ライブラリをミラーリングするため「通常」です。


戻り値の型を推定します

イテレータの「背後」にある値の型を取得するには、 std::iterator_traits 、特に埋め込み型value_type に使える;

typedef typename std::iterator_traits<InputIt>::value_type Result;
// .. default initialise
Result sum = Result{}; // or Result() if earlier than C++11

デザインの選択

(オプション2のバリエーション)の機能を設計します。

  • 範囲を受け入れる[最初、最後)
  • 使用する std::iterator_traits(ポインタでも機能します)戻り値の型を推測します
  • C++ 11のデフォルトの初期化を使用して結果を初期化する

次のように:

template <class Iterator, class U = typename std::iterator_traits<Iterator>::value_type>
U sum(Iterator first, Iterator last)
{
    U sum = U{};
    for (auto it = first; it != last; ++it) {
        sum += *it;
    }
    return sum;
}

テンプレート引数を減らした代替案。

template <class Iterator>
typename std::iterator_traits<Iterator>::value_type sum(Iterator first, Iterator last)
{
    using U = typename std::iterator_traits<Iterator>::value_type;
    U sum = U{};
    for (auto it = first; it != last; ++it) {
        sum += *it;
    }
    return sum;
}
15
Niall