11
template<class T>
struct is_iterator
{
    static const bool value = ??? // What to write ???
};

int main()
{
    assert(false == is_iterator<int>::value);
    assert(true == is_iterator<vector<int>::iterator>::value);
    assert(true == is_iterator<list<int>::iterator>::value);
    assert(true == is_iterator<string::iterator>::value);
    assert(true == is_iterator<char*>::value); // a raw pointer is also an iterator
}

問題は、5 つの assert ステートメントを渡す方法です。

4

5 に答える 5

15

数年後にここに来て、C++11 と C++14 がそのようなことをより簡単にできるようにします。イテレータは、本質的に、逆参照可能でインクリメント可能なものです。入力 iteratorの場合も同様です。後者で行きましょう - それはあなたが望むもののように見えるからです.

最も簡単なバージョンは、次を使用することvoid_tです。

template <typename... >
using void_t = void;

規範事例:

template <typename T, typename = void>
struct is_input_iterator : std::false_type { };

有効なケースの特殊化:

template <typename T>
struct is_input_iterator<T,
    void_t<decltype(++std::declval<T&>()),                       // incrementable,
           decltype(*std::declval<T&>()),                        // dereferencable,
           decltype(std::declval<T&>() == std::declval<T&>())>>  // comparable
    : std::true_type { };

エイリアス:

template <typename T>
using is_input_iterator_t = typename is_input_iterator<T>::type;

iterator_categoryオーバーロード解決を使用した面倒な C++03 スタイルのチェックに依存したり使用したりする必要はありません。式 SFINAE はその場所にあります。


Wakely 氏がコメントで指摘しているように、[iterator.traits] は次のことを要求します。

Iteratorがイテレータの型である場合、その型が必要です

iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category

それぞれ、反復子の差分型、値型、および反復子カテゴリとして定義されます。

したがって、 iterator トレイトを定義して、単純にそれをチェックできます。

template <class T, class = void>
struct is_iterator : std::false_type { };

template <class T>
struct is_iterator<T, void_t<
    typename std::iterator_traits<T>::iterator_category
>> : std::true_type { };

iterator_traits<T>::iterator_categoryの形式が正しくない場合はT、イテレータではありません。

于 2015-07-14T14:28:14.403 に答える
6
template<class T>
struct is_iterator
{   
    static T makeT();
    typedef void * twoptrs[2];  // sizeof(twoptrs) > sizeof(void *)
    static twoptrs & test(...); // Common case
    template<class R> static typename R::iterator_category * test(R); // Iterator
    template<class R> static void * test(R *); // Pointer

    static const bool value = sizeof(test(makeT())) == sizeof(void *); 
};
于 2010-12-02T14:55:43.387 に答える
3

iterator_categoryこれは を使用して行うことができ、正確な手法は のwikiページでSFINAE見つけることができます。これは 100% の方法ではありませんが、適切なイテレーターはすべて、イテレーターに共通の typedef を提供する必要があり、iterator_category はイテレーターに固有のものです。また、TYPE が単なるポインターであるかどうかを確認することも忘れないでください。ポインターは反復子です。SFINAE

于 2010-12-02T14:24:01.377 に答える
2

元の投稿者は、実際には InputIterator を識別する方法を求めていることを明らかにしました ( http://en.cppreference.com/w/cpp/concept/InputIteratorを参照)。彼らはイテレータをインクリメントおよび逆参照できるようにしたいからです。これには、標準 C++11 の非常に単純な SFINAE ソリューションがあります。たとえば、gcc STL のソリューションに似ています。

template<typename InputIterator>
using RequireInputIterator = typename
    std::enable_if<std::is_convertible<typename
                                       std::iterator_traits<InputIterator>::iterator_category,
                                       std::input_iterator_tag>::value>::type;

...

// Example: declare a vector constructor from a pair of input iterators.
template <typename InputIterator, typename = RequireInputIterator<InputIterator> >
    MyVector(InputIterator first, InputIterator last) { /* ... */ };

これは、Armen Tsirunyan がイテレータ自体に必要であると考えた typedef を定義するイテレータ型特性クラスに依存しています。(イテレータはこれらの typedef を提供できますが、イテレータとしてネイキッド ポインターを使用するために必要な特性クラスでそれらを提供することもでき、標準ライブラリの実装はそうする必要があります。)

于 2016-10-24T20:05:20.373 に答える
1
template < class T, class Enabler = void >
struct is_iterator : public boost::false_type { };

template < class T >
struct is_iterator< T, typename boost::enable_if_c<
        sizeof(*(*(T*)0)) + sizeof((*(T*)0)++) + sizeof(++(*(T*)0)) +
        sizeof((*(T*)0) == (*(T*)0)) + sizeof((*(T*)0) != (*(T*)0)) +
        sizeof((*(T*)0) = (*(T*)0)) >::type > : public boost::true_type { };
于 2012-07-18T06:51:53.177 に答える