2012-02-11 31 views
2

主にデバッグの目的でstdコンテナのストリーム演算子を記述しようとしています。std :: set SFINAEの問題でis_containerの特性が失敗する

I持って次のコード:

#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; 
} 

私は、これは(建設的なコメントが感謝)完璧にはほど遠いです承知していますが、私が午前問題は、それがベクトル、両端キューおよびリストのために素晴らしい作品が、に失敗したということですなぜなら、セットにはイテレータのインターフェイスがまだ開始され、終了しているからです。

ありがとうございました。

EDIT: グラム上でテスト++(GCC)4.6.2 2012012 打ち鳴らすバージョン3.0

EDIT2:今、私はそれがないと主張することはできませんので、私はそれが一種のdecltypeを使用して作業してしまったしかしそれがサブ最適です私が期待するもの(イテレータを返す)。

私は、セットが最初に戻ってきたことを正確には知りません。もし誰かがTMPをデバッグする方法を持っていれば、それは良いでしょう。

+1

私は[プリティプリンタ](http://stackoverflow.com/questions/4850473/pretty-print-cで 'is_container'形質のいくつかのフォームを持っています-stl-containers)を使用してください。 –

+0

@KerrekSBありがとう、私はそれを見ていきますが、これは実際に私がこのようなものを得るテストであるので、私はそれを正確に行い、それを働かせようとします。 – 111111

+0

これは不要です。これを試してみてください:http://ideone.com/gBx6P –

答えて

4

std::set<T>には1組の不変イテレータのみがあるので、とend()のバージョンはconstと宣言されています。他のコンテナが署名あなたにマッチconstbegin()の非constバージョンとend()の両方を持っている

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

:それはstd::set<T>の定義は、この(それは前に名前空間stdで宣言されたと仮定した場合)のようになり、あります頼む。 std::setにはこれがありません。私はこのための最も簡単な回避策があるとは思っていません。

つまり、sizeof(char)sizeof(long)とすることができます。 yesno種類が異なるサイズを持っていることを保証する最も簡単な方法は、例えば、同じタイプのために、異なるサイズの配列への参照を使用することです:

typedef char (&yes)[1]; 
typedef char (&no)[2]; 
... 
enum { value = sizeof(some_expression) == sizeof(yes) }; 
+0

私は近くにいた、私は配列の事を試みたが、参照する必要があったことを認識していない。それのほうがいい。また、セットにはconstイテレータのみがあることはわかりませんでした。私はこれによって投げられたと思います:http://en.cppreference.com/w/cpp/container/set/begin私は本当に私が列挙型のビットを気にしないと思っていません。私はC++ 11をターゲットにしていますので、vc6.0の癖は私のコードを難読化するのに十分な理由です。とにかく再びありがとう。 – 111111

+0

さて、 'enum'ビットは" VC6.0 "ではあまり意味がありませんが、値の定義を必要とするものに値を渡すことになりました。あなたの 'static bool const value = ...'はまだ初期値が与えられていますが、**定義ではありません! C++ 2011を使用している場合は、 'static bool constexpr value = ...'を使用してクラス定義の値を定義することもできます(ただし、 'constexpr'修飾子がどこにあるかは完全にはわかりませんがつまり、この表記法はやや間違っている可能性があります)。 –

+0

"constexpr static bool value"はgccでうまく機能しました – 111111

2

後者返すので、それはvectorのためではなく、setの作品const_iteratorbegin/endの機能です。変更:

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

へ:

typename T::const_iterator(T::*)() const, 
関連する問題