2011-09-29 18 views
5

以下のサンプルコードでは、boost :: tupleを最初のテンプレート引数から暗黙的に作成できることを示しています。 そのため、私は<<オペレータを書くことができません。あいまいになるからです。boost :: tupleの `<<`演算子を書くには?

また、ostringstream& << floatもあいまいである理由はわかりません。これには暗黙的な構造はありません。なぜこれもあいまいなエラーをもたらすのでしょうか?

#include <iostream> 
#include <boost/tuple/tuple.hpp> 
#include <sstream> 
#include <string> 

using namespace std; 

class Myclass 
{ 
}; 

typedef boost::tuple<int,float,Myclass> Mytuple; 

ostringstream& operator<<(ostringstream& os_, Mytuple tuple_) 
{ 
    float f = tuple_.get<1>(); 
    //os_ << (int)tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY? 
    //os_ << tuple_.get<1>();  // No Clue Why this is ambiguous. 
    //os_ << tuple_.get<2>();  // Error because no matching operator. Fine. 
    return os_; 
} 

int main() 
{ 
    Mytuple t1; 
    t1 = 3;  // Working because int is implicitly converted into Mytuple!! WHY? 
    //t1 = 3.0f; // Error because no matching constructor. Fine. 
    return 0; 
} 

エラーMesasge:

tupleTest2.C:18: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:

+0

'boost :: tuple'はすでに' operator << 'を持っています。私はそれがあなたが得ているエラーにつながるが、それは関連しているかもしれません。 –

+0

また、 'boost :: tuple'はタプル要素の0..nのコンストラクタを持っていますので、あなたは' int'から変換可能なコンストラクタ 'Mytuple(int)'を持っています。 –

+0

これはgcc 4.5とgcc 4.7の実験ではうまくコンパイルできます。どのコンパイラのバージョンを使用していますか? – rodrigo

答えて

4

問題はタプルではなく、あなたの演算子ではありません。これは正常に動作します:ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)が許可されています

ostream& operator<<(ostream& os_, Mytuple tuple_) 
{ 
    os_ << tuple_.get<0>(); // Error because int is implicitly converted into Mytuple. WHYY? 
    os_ << tuple_.get<1>();  // No Clue Why this is ambiguous. 
    //os_ << tuple_.get<2>();  // Error because no matching operator. Fine. 
    return os_; 
} 

問題はostringstreamは、この署名を持っているのostreamからoperator<<を継承するということです。次いで

ostream& operator<<(ostream& os, T t) 

は、(C言語++で使用可能なすべてのタイプの変更T、ここoperator<< reference page

EDIT

を参照()タプルことなく簡単な例である:

ostringstream& operator<<(ostringstream& os_, Mytuple tuple_) 
{ 
    const int i = tuple_.get<0>(); 
    os_ << i; // error in this line 
    return os_; 
} 

エラーは次のとおりです。

dfg.cpp: In function ‘std::ostringstream& operator<<(std::ostringstream&, Mytuple)’: 
dfg.cpp:18: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: 
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/ostream.tcc:111: note: candidate 1: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>] 
dfg.cpp:14: note: candidate 2: std::ostringstream& operator<<(std::ostringstream&, Mytuple) 

上記のエラーメッセージは言う:2つの事業者operator<<(ostream&,...)operator<<(ostringstream&,...). This also raises another question : why on earth do you needオペレータ< <(ostringstream &、...)との間で選択することはできませんか `?

+0

問題は何だったのか説明できますか? –

+0

それは動作します。しかし、なぜこれはうまくいくのですか?「ストリングストリーム」はうまくいかないのですか?実際には、私はこれを私のカスタムストリームで使いたいと思っています。 – balki

+0

私は分かりません。はい、ostreamにはプリミティブ型のoperator <<があります。なぜカスタムクラスを取るカスタム演算子ではあいまいであるべきですか? – balki

3

あなたは

os << tuple_.get<0>(); 

を書くときに、両方のパラメータに一致する機能がありません。代わりに、コンパイラは、いずれかのパラメータに暗黙的な変換を適用するための選択肢を持っている

std::ostream << int 

または

std::ostringstream << MyTuple 

後者はタプルの要素数までの任意の数の引数を取ることができboost::tupleコンストラクタで起こります。 (floatintに変換可能であるため、そしてfloatと、それは、失敗します。)

ストリーム演算子をオーバーロードすると、ostreamあるいはbasic_ostream<CharT, Traits>(左側として基本クラスを使用し


編集:は、 を最初に引数にキャストしてコールの曖昧さを排除できます。それはオペレータチェーンでは動作しませんので、

ostringstream& operator<<(ostringstream& os_, Mytuple tuple_) 
{ 
    static_cast<std::ostream&>(os_) << tuple_.get<0>(); 
    static_cast<std::ostream&>(os_) << tuple_.get<1>();  
    static_cast<std::ostream&>(os_) << tuple_.get<2>();  // Error because no matching operator. Fine. 
    return os_; 
} 

はしかし、ostringstreamでオペレータをオーバーロードすることは、まだ悪い考えです。

MyTuple a, b; 
ostringstream ss; 
ss << a << ' ' << b; 

呼び出します:

1)ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)

2)ostream& ostream::operator<<(char)

3)ostream& operator<<(ostream&&, boost::tuple<int,float,Myclass>

+1

次のように書いてください。 'os.operator <<(tuple_.get <1>());' – rodrigo

1

タイプに::std::ostreamを使用するためにあなたを伝える代わりに、すべての人々 ::std::ostringstreamは絶対的です正しい。あなたはそのように::std::ostringstreamを使用すべきではありません。

しかし、私の主な牛肉はあなたのコードで一般性が苦しいです。 1つの特定のタプルタイプでのみ動作し、それらのすべてではありません。

を使用してメンバーを個別に書き込むことができるタプルのC++ 0xに::std::tupleoperator <<を書きました。これは、Boostのタプル型で動作するように比較的簡単に変換できます。ここにあります:

template < ::std::size_t fnum, typename tup_type> 
void print_fields(::std::ostream &os, const tup_type &val) 
{ 
    if (fnum < ::std::tuple_size<tup_type>::value) { 
     ::std::cerr << "Fred " << fnum << '\n'; 
     os << ::std::get<fnum, tup_type>(val); 
     if (::std::tuple_size<tup_type>::value > (fnum + 1)) { 
     os << ", "; 
     } 
     print_fields<fnum + 1, tup_type>(os, val); 
    } 
} 

template < ::std::size_t fnum, typename... Elements> 
class field_printer; 

template <typename... Elements> 
class field_printer<0, Elements...> { 
public: 
    typedef ::std::tuple<Elements...> tup_type; 

    static void print_field(::std::ostream &os, const tup_type &val) { 
    } 
}; 

template < ::std::size_t fnum, typename... Elements> 
class field_printer { 
public: 
    typedef ::std::tuple<Elements...> tup_type; 

    static void print_field(::std::ostream &os, const tup_type &val) { 
     constexpr auto tupsize = ::std::tuple_size<tup_type>::value; 
     os << ::std::get<tupsize - fnum, Elements...>(val); 
     if (fnum > 1) { 
     os << ", "; 
     } 
     field_printer<fnum - 1, Elements...>::print_field(os, val); 
    } 
}; 

template <class... Types> 
::std::ostream &operator <<(::std::ostream &os, const ::std::tuple<Types...> &val) 
{ 
    typedef ::std::tuple<Types...> tup_type; 
    os << '('; 
    field_printer< ::std::tuple_size<tup_type>::value, Types...>::print_field(os, val); 
    return os << ')'; 
} 

これはタプルを"(element1, element2, ...elementx)"として表示します。

関連する問題