2011-09-29 67 views
5

Trong mã mẫu bên dưới, nó cho thấy rằng tăng :: tuple có thể được tạo ra ngầm từ đối số mẫu đầu tiên. Do đó tôi không thể viết một toán tử << vì nó trở nên mơ hồ.Cách viết toán tử `<<` cho boost :: tuple?

Ngoài ra tôi không hiểu tại sao ostringstream& << float cũng không rõ ràng. Điều này không có bất kỳ công trình ngầm nào. Tại sao điều này cũng cung cấp cho lỗi mơ hồ?

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

Lỗi 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' đã có một toán tử' 'giống như vậy. Tôi không thấy làm thế nào mà dẫn đến các lỗi bạn đang nhận được nhưng nó có thể có liên quan. –

+0

Cũng 'boost :: tuple' có các hàm tạo cho 0..n của các phần tử tuple, do đó, bạn có một hàm tạo' Mytuple (int) ', nó làm cho nó có thể chuyển đổi từ' int'. –

+0

Nó biên dịch tốt cho tôi - có thể là - với thử nghiệm gcc 4.5 và gcc 4.7. Bạn đang sử dụng phiên bản trình biên dịch nào? – rodrigo

Trả lời

4

Vấn đề không phải là với các tuple, nhưng với nhà điều hành của bạn. Đây hoạt động tốt:

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

Vấn đề là các ostringstream kế thừa operator<< từ ostream, trong đó có chữ ký này: ostringstream& operator<<(ostringstream& os_, Mytuple tuple_) được cho phép. Sau đó,

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

(thay đổi T với tất cả các loại có sẵn trong C++, xem operator<< reference page

EDIT

Đây là một ví dụ đơn giản (không có tuple):

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

và lỗi hiện tại là:

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) 

Các thông báo lỗi trên cho biết: nó không phải là có thể lựa chọn giữa hai nhà khai thác operator<<(ostream&,...)operator<<(ostringstream&,...). This also raises another question : why on earth do you need hành < < (ostringstream & ...) `?

+0

Bạn có thể giải thích vấn đề là gì không? –

+0

Nó hoạt động. Nhưng tại sao điều này làm việc nhưng 'ostringstream' không hoạt động? Thực ra tôi muốn điều này hoạt động với luồng tùy chỉnh của tôi. – balki

+0

Tôi không hiểu. Có, ostream có toán tử << cho các kiểu nguyên thủy. Tại sao điều đó nên mơ hồ với một toán tử tùy chỉnh có một lớp tùy chỉnh? – balki

3

Khi bạn viết

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

không có chức năng phù hợp với cả hai tham số. Thay vì trình biên dịch có một sự lựa chọn để áp dụng một chuyển đổi ngầm ở hai tham số

std::ostream << int 

hoặc

std::ostringstream << MyTuple 

Sau đó sẽ xảy ra với boost::tuple constructor có thể mất bất kỳ số lượng đối số lên đến số nguyên tố tuple . (Và với float nó không thành công, bởi vì float là mui trần để int.)

Khi quá tải khai thác suối, sử dụng các lớp cơ sở như ở phía bên tay trái (ostream hoặc thậm chí basic_ostream<CharT, Traits>


Edit:. Bạn có thể phân biệt cuộc gọi bằng cách gửi đối số đầu tiên.

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

Tuy nhiên, quá tải toán tử với ostringstream vẫn là một ý tưởng tồi, bởi vì nó sẽ không làm việc với nhà điều hành loạt.

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

sẽ gọi:

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

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

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

+1

Nó sẽ dễ dàng hơn để phân định văn bản: 'os.operator << (tuple_.get <1>());' – rodrigo

1

Tất cả những người nói cho bạn để sử dụng ::std::ostream cho kiểu thay vì ::std::ostringstream là tuyệt đối ly đúng. Bạn không nên sử dụng ::std::ostringstream theo cách đó.

Nhưng thịt bò chính của tôi với mã của bạn là sự thiếu hụt tính tổng quát. Nó chỉ hoạt động cho một loại bộ dữ liệu cụ thể và không phải tất cả chúng.

Vì vậy, tôi đã viết operator << cho ::std::tuple bằng C++ 0x hoạt động cho bất kỳ bộ nào mà thành viên có thể được viết riêng bằng cách sử dụng operator <<. Nó có thể được dịch tương đối dễ dàng để làm việc với loại tuple của Boost. Dưới đây là:

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 << ')'; 
} 

Điều này in ra bộ tẩu như "(element1, element2, ...elementx)".

Các vấn đề liên quan