2011-09-29 23 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的構造函數,所以你的構造函數爲'Mytuple(int)',它可以從'int'轉換。 –

+0

它編譯罰款 - 因爲它應該與gcc 4.5和gcc 4.7實驗。你使用什麼編譯器版本? – rodrigo

回答

4

的問題是不與元組,但與運營商。這工作得很好:

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<<ostringstream& operator<<(ostringstream& os_, Mytuple tuple_)是允許的。然後用在C++中的所有可用的類型的

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

(變化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) 

上述錯誤信息說:這是不可能的兩家運營商operator<<(ostream&,...)operator<<(ostringstream&,...). This also raises another question : why on earth do you need運營商< <之間進行選擇(ostringstream &,...)`?

+0

你能解釋一下問題是什麼嗎? –

+0

它的工作原理。但爲什麼這個工作,但'ostringstream'不起作用?其實我希望這與我的自定義流一起工作。 – balki

+0

我不明白。是的,ostream有operator <<用於基本類型。爲什麼這應該與需要自定義類的自定義運算符混淆? – balki

3

當你寫

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

沒有函數,該函數的參數相匹配。相反,編譯器有選擇地對任一參數適用的隱式轉換

std::ostream << int 

std::ostringstream << MyTuple 

後者將與boost::tuple構造,可以採取任何數量的參數最多的元組元素的數量發生。 (並與float失敗,因爲float可以轉換爲int。)

當超載流運營商,使用基類如左手側(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

但我的主要牛肉與你的代碼是令人痛心的缺乏普遍性。它只適用於一種特定的元組類型,而不是全部。

所以我寫了operator <<::std::tuple在C++ 0x,任何元組成員都可以單獨使用operator <<寫作。使用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)"