2012-05-08 16 views
4

次のコードを考慮してください。私はostreamにベクトルのベクトルを出力しようとしています。ostreamへのベクトルのベクトルを出力

#include <iterator> 
#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 

template<typename T> 
std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) { 
    using namespace std; 
    copy(v.begin(), v.end(), ostream_iterator<T>(os, "\n")); 
    return os; 
} 

int main() { 
    using namespace std; 
    vector<string> v1; 
    cout << v1; 
    vector<vector<string> > v2; 
    cout << v2; 
    return 0; 
} 

文字列のベクトルを出力するステートメントが機能します。私が文字列のベクトルのベクトルを出力するものはありません。私はg ++ 4.7.0を使用しています。私は、-std = C++ 11フラグなしで&を試しました。 C++ 11モードでは、エラーの半ページにこの行が表示されます。

error: cannot bind 'std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >::ostream_type {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&' 

私はそれが何を意味するかはわかりません。誰かが私に説明することができますか?私は多かれ少なかれrvalue参照が何であるか知っていますが、std::basic_ostream<char>std::basic_ostream<char>&&にバインドしない理由がわかりません。たぶん私は十分にそれをよく知りません。これを行うにはよりよい方法がありますか?

ありがとうございます。

+0

これについて考えると、 'vector >' case、 "\ n"はキャスト可能で、ベクトル 'にする必要があります。原因のそれは動作しません –

+0

@ J - 16SDiZ:何のことを言っている?いいえ、それはありません。 –

+0

@ J-16SDiZ:いいえ、それは単に間違っています。 – Nawaz

答えて

8

あなたが取得しているエラーがあります少し誤解を招く私はあなたのプログラムをコンパイルしようとしたとき、私はテンプレートの嘔吐物にかなり掘っていた、と私は何が起こっていたか、私は思ってしまっ:基本的に

error: no match for 'operator<<' in '*((std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >*)this)->std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >::_M_stream << __value' 

、コピー・アルゴリズムを呼び出したときに、それが使用さ出力のイテレータは、< <演算子を名前空間stdから使用しました。一度そこに参照すると、std名前空間にテンプレートベクトル<>のオーバーロードが見つかります(これはITが存在するためです)。

だから、あなたがしなければならないことは、名前空間stdのベクトルテンプレートのストリーム演算子を宣言することです。 namespace std {}でコードを囲んで、何が起こるかを見てください...

基本的にはstd :: vector <を修正し、これまでになかった動作を追加しています。これを行うことは非標準であり、未定義であり、容易にあなたの方法で得ることができます。あなたは他の選択肢を検討するかもしれません。


私はこれがkoenigルックアップであることについて間違っていました。それは問題ではありません。ここではクラス内で何が起こっているのかに似た名前が隠れています。ここでは、ベースに何かのオーバーロードが宣言されています(オーバーライドではありません)。

標準の名前空間では、いくつかの '< <'演算子が宣言されています。これらは基本的にoperator <<という名前の関数です。あなたがグローバル名前空間またはそれでfunをという名前のすべての機能を持たない任意の名前空間からfun(int)を使用することができます

void fun(int); 

namespace Test { 

    void fun() { fun(3); } 

} 

int main() { 
    Test::fun(); 
} 

注:本質的には何を持っていることはこれです。 Test名前空間からは使用できません。

これは、グローバルに宣言された演算子< <の使用が、グローバル名前空間から正常に機能しますが、std名前空間内からではありません。 std名前空間には、既に提供しようとしているオーバーロードと同じ名前のものがあり、オーバーロードはstd内のすべてのものから隠されています。あなたが宣言を使うことができれば、それは違うでしょう。

+0

標準で許可されていないstd名前空間に物を置くのはそれですか?それにもかかわらず、私は本当に実際の実装で実際に問題を引き起こすのではないかと疑い、私にとってはうまくいくようです。 –

+0

うん、それは働いた!ありがとう! 私は完全に理解していません。ベクトル(Tが文字列の場合)のオーバーロードがグローバル名前空間で見つかった場合、どのようにして2レベルルックアップの第2レベルで過負荷を見つけることができませんか? std :: operator <<を探すためにstd名前空間の出力イテレータコードが記述されていますか? 私はベンジャミンの懸念に同意します - これは奨励されているものですか? – Ashley

+0

これは未定義の動作ですが、行う必要があることをやる必要があります。既に定義されていれば既に動作します。 –

4

あなたは、このユーティリティライブラリが必要になります。


あなたは(自分自身を教えるように)これを自分で行いたい場合は、あなたのように2つのオーバーロードを定義する必要があります。

  • std::vector<T>の場合:

    std::vector<std::vector<T>>については
    template<typename T> 
    std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) { 
        using namespace std; 
        copy(v.begin(), v.end(), ostream_iterator<T>(os, "\n")); 
        return os; 
    } 
    
  • template<typename T> 
    std::ostream &operator <<(std::ostream &os, const std::vector<std::vector<T>> &v) { 
        using namespace std; 
    
        //NOTE: for some reason std::copy doesn't work here, so I use manual loop 
        //copy(v.begin(), v.end(), ostream_iterator<std::vector<T>>(os, "\n")); 
    
        for(size_t i = 0 ; i < v.size(); ++i) 
         os << v[i] << "\n"; 
        return os; 
    } 
    

あなたはこれらのオーバーロードを使用している場合は、その後、彼らは一緒に再帰的にこれらのケースを処理します:

std::vector<int> v; 
std::vector<std::vector<int>> vv; 
std::vector<std::vector<std::vector<int>>> vvv; 
std::vector<std::vector<std::vector<std::vector<int>>>> vvvv; 

std::cout << v << std::endl; //ok 
std::cout << vv << std::endl; //ok 
std::cout << vvv << std::endl; //ok 
std::cout << vvvv << std::endl; //ok 
+0

これを動作させるために何か他にはありますか?それは私のために働かないので。 http://ideone.com/A2d67 –

+1

@BenjaminLindley:なぜそれはうまくいかないのかわかりません。おそらくコンパイラのバグですか?とにかく、手動ループは正常に動作します。 – Nawaz

+0

'ostream_iterator'が' std'名前空間にあり、 'vector'もそうであるため、他のバージョンは動作しませんでした。そのため、ADLはあなたが定義した 'operator <<'テンプレートを見つけられず、コンパイルに失敗します。 –

関連する問題