4

ポインターになる可能性のある 2 つのイテレーターを受け入れる関数テンプレートが必要です。2 つの引数が random_access イテレータの場合、戻り値の型をオブジェクトにしたい

std::iterator<random_access_iterator_tag, ...>タイプ

そうでなければ

std::iterator<bidirectional_iterator_tag, ...>タイプ。

また、引数が双方向反復子でもポインターでもない場合、コードがコンパイルを拒否するようにします。Boostなどのサードパーティのライブラリに依存することはできません

ポインターだけでなく双方向イテレーターを受け入れるように、この関数の署名を手伝っていただけませんか。

私が考えることができる1つの部分的な解決策は次のとおりです

template<class T>
T foo( T iter1, T iter2) {
  const T tmp1 = reverse_iterator<T>(iter1);
  const T tmp2 = reverse_iterator<T>(iter2);
  // do something
}

アイデアは、双方向でない場合、コンパイラはそこから reverse_iterator を構築させないということです。

4

2 に答える 2

3

enable_ifこれは、イテレータ タグに基づく例です。指定された T にiterator_categorytypedef がなく、オーバーロードの解決中にオーバーロードが考慮されない場合、置換は失敗します。

C++11 は使用できないため、enable_ifおよびのリファレンス ページをis_same参照して、自分で実装する方法を確認してください。

#include <iterator>
#include <type_traits>
#include <iostream>
#include <vector>
#include <list>

template<typename T>
typename
std::enable_if<
    std::is_same<
        typename T::iterator_category,
        std::bidirectional_iterator_tag
    >::value,
    T
>::type
foo(T it)
{
    std::cout << "bidirectional\n";
    return it;
}

template<typename T>
typename
std::enable_if<
    std::is_same<
        typename T::iterator_category,
        std::random_access_iterator_tag
    >::value,
    T
>::type
foo(T it)
{
    std::cout << "random access\n";
    return it;
}

// specialization for pointers

template<typename T>
T* foo(T* it)
{
    std::cout << "pointer\n";
    return it;
}

int main()
{
    std::list<int>::iterator it1;
    std::vector<int>::iterator it2;
    int* it3;
    std::istream_iterator<int> it4;
    foo(it1);
    foo(it2);
    foo(it3);
    //foo(it4); // this one doesn't compile, it4 is an input iterator
}

実例

@JonathanWakely のコメントによると、std::iterator_traitsを使用すると、ポインターの特殊化を取り除くことができます。そのtypename T::iterator_category部分は次のようになります。

typename std::iterator_traits<T>::iterator_category
于 2012-11-12T20:09:51.707 に答える
2

std::enable_if に依存しない、以前の回答よりも少し単純です:

namespace detail
{
    template<class T>
    T do_foo(T iter1, T iter2, std::random_access_iterator_tag t)
    {
        cout << "do_foo random_access" << endl;
        return iter1;
    }
    template<class T>
    T do_foo(T iter1, T iter2, std::bidirectional_iterator_tag t)
    {
        cout << "do_foo bidirectional" << endl;
        return iter1;
    }

}
template<class T>
void foo(T iter1, T iter2)
{
    typename std::iterator_traits<T>::iterator_category t;
    detail::do_foo(iter1, iter2, t);
}

int main (int argc, const char * argv[])
{
    std::vector<int> v;
    foo(v.begin(), v.end());
    std::list<int> l;
    foo(l.begin(), l.end());
    return 0;
}

このソリューションは、std::random_access_iterator_tag または std::bidirectional_iterator_tag (存在する必要があります) から派生した他の iterator_categories もサポートしますが、std::same<> は厳密なカテゴリの等価性をチェックします。

于 2012-11-13T15:42:37.987 に答える