2

主にデバッグの目的で、std コンテナー用のストリーム演算子を作成しようとしています。

次のコードがあります。

#include <type_traits>
#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>
#include <functional>

#include <vector>
#include <set>
#include <deque>


template<typename Container>
struct is_container
{
    typedef char no;
    typedef long yes;


    template<typename A, A, A>
    struct is_of_type;

    template<typename T>
            static yes& is_cont(
                            is_of_type
                            <
                                    typename T::iterator(T::*)(), 
                                    &T::begin,
                                    &T::end
                            >*);


    template<typename T>
    static no& is_cont(...);        //any other

    template<typename C, bool B>
    struct is_class_is_container
    {
            const static bool value=sizeof( is_cont<C>(nullptr) )==sizeof(yes);
    };

    template<typename C>
    struct is_class_is_container<C, false>
    {
            const static bool value=false;
    };

    const static bool value = is_class_is_container
            <
                    Container, 
                    std::is_class<Container>::value 
            >::value;
};

template<typename T>
    typename std::enable_if
    < is_container<T>::value, std::ostream >::type& 
    operator<<(std::ostream& os, const T& a)
{
    os << '[';
    std::copy(a.begin(), a.end(), std::ostream_iterator<typename T::value_type>(os, ", "));
    os << ']';
    return os;
}

私はこれが完璧とはほど遠いことを認識しています (建設的なコメントを歓迎します) が、私が抱えている問題は、ベクター、deque、およびリストに対してはうまく機能するが、セットでは一致しないことです。セットにはまだイテレーター インターフェイスがあるため、その理由はわかりません始まりと終わり。

ありがとう。

編集:g ++(GCC)4.6.2 2012012でテスト済みclangバージョン3.0

EDIT2: decltype を使用して動作するようになりましたが、これは最適ではありません。これは、期待どおりの動作をする(イテレータを返す)と断言できないためです。

そもそもセットが何を返したのか正確にはわかりません。おそらく誰かがTMPをデバッグする方法を持っていれば、それは良いでしょう。

4

2 に答える 2

4

std::set<T>には不変イテレータのセットが 1 つしかないため、 であると宣言されている and のバージョンは 1つだけbegin()です。つまり、 の定義は次のようになります (以前に名前空間で宣言されていたと仮定します):end()conststd::set<T>std

template <typename T>
class std::set
{
public:
    class            iterator;
    typedef iterator const_iterator;
    ...
    const_iterator begin() const;
    const_iterator end() const;
    ...
};

他のコンテナには、要求する署名と一致するバージョンconstと非constバージョンの両方があります。これはありません。ただし、これに対する最も簡単な回避策が何であるかはわかりません。begin()end()std::set

とはいえ、sizeof(char)であることが許されますsizeof(long)yes型と型のサイズが異なることを保証する最も簡単な方法noは、同じ型に対して異なるサイズの配列への参照を使用することです。次に例を示します。

typedef char (&yes)[1];
typedef char (&no)[2];
...
enum { value = sizeof(some_expression) == sizeof(yes) };
于 2012-02-11T18:05:18.937 に答える
2

後者はfor /関数を返すため、 for では機能しますが、 for では機能しvectorません。変化する:setconst_iteratorbeginend

typename T::iterator(T::*)(), 

に:

typename T::const_iterator(T::*)() const, 
于 2012-02-11T18:15:01.033 に答える