2011-09-16 44 views
6

Tôi đang cố gắng để làm điều đó theo cách này:cách toán tử quá tải << cho một mảng trong C++?

template <typename T> 
ostream &operator<<(ostream &os, T &arr) 
{ /*...*/ } 

Nhưng có thể T đại diện cho một mảng? Có đúng khi quá tải toán tử << cho một mảng không?


EDIT:

Theo lời khuyên Kerrek SB của, ở đây là thực hiện của tôi cho <<:

template <typename T, unsigned int N> 
ostream &operator<<(ostream &os, const T (&arr)[N]) 
{ 
    int i; 
    for(i = 0; i < N; i++) 
     os << arr[i] << " "; 
    os << endl; 
    return os; 
} 

là thực hiện của tôi phải không? Tôi gặp lỗi biên dịch.

Trả lời

7

Bạn có thể làm điều này:

template <typename T, unsigned int N> 
std::ostream & operator<<(std::ostream & os, const T (&arr)[N]) 
{ 
    // .. 
    return os; 
} 

này chỉ hoạt động cho mảng thời gian biên dịch, tất nhiên. Lưu ý rằng bạn không được phép tạo mẫu này khi T là loại được tích hợp sẵn hoặc loại trong không gian tên std!

Có lẽ tốt nhất để làm cho nội tuyến này nếu có thể, vì bạn sẽ gây ra một sự khởi tạo riêng biệt cho mỗi N. (Ví dụ: pretty printer có ví dụ về điều này.)

Bạn sẽ thấy mẫu chăn giới thiệu một sự mơ hồ, vì os << "Hello" hiện có hai lần quá tải: mẫu phù hợp với const char (&)[6] và quá tải (không phải mẫu) decay-to-pointer const char *, cả hai đều có trình tự chuyển đổi giống hệt nhau. Chúng ta có thể giải quyết điều này bằng cách vô hiệu hóa quá tải của chúng tôi đối với mảng char:

#include <ostream> 
#include <type_traits> 

template <typename T, unsigned int N> 
typename std::enable_if<!std::is_same<T, char>::value, std::ostream &>::type 
operator<<(std::ostream & os, const T (&arr)[N]) 
{ 
    // .. 
    return os; 
} 

Trong thực tế, để được thậm chí tổng quát hơn bạn cũng có thể làm cho basic_ostream thông số mẫu tham số:

template <typename T, unsigned int N, typename CTy, typename CTr> 
typename std::enable_if<!std::is_same<T, char>::value, 
         std::basic_ostream<CTy, CTr> &>::type 
operator<<(std::basic_ostream<CTy, CTr> & os, const T (&arr)[N]) 
{ 
    // .. 
    return os; 
} 

Theo quan điểm của thực tế là T phải là loại do người dùng xác định, thậm chí bạn có thể thay thế is_same<T, char> bằng is_fundamental<T> để kiểm tra thêm một chút (nhưng người dùng vẫn không được sử dụng loại này cho mảng các loại thư viện chuẩn).

+0

cảm ơn, nhưng tôi don 't hiểu lý do tại sao nó gây ra một instantiation riêng biệt cho mỗi N nếu không thực hiện nội tuyến? – Alcott

+0

Vâng, đó là một mẫu, vì vậy mỗi mẫu thể hiện có thể kết thúc dưới dạng một hàm riêng biệt trong tệp nhị phân của bạn. Nếu bạn nội tuyến, bạn có thể có thể tránh được toàn bộ cuộc gọi hàm, mặc dù điều này là cuối cùng lên đến trình biên dịch. –

+0

.Với toán tử << có 2 mẫu args, làm thế nào tôi có thể chỉ định arg N thứ hai? Rõ ràng tôi không thể chỉ đơn giản là sử dụng "cout << ar;", tôi có thể? – Alcott

3

Một cách khác bạn có thể làm được điều này sẽ là một cái gì đó như sau:

template<typename T> 
ostream& operator<<(ostream &out, const std::pair<T, int>& array) 
{ 
    //...code 
    return out; 
} 

đâu T sẽ mất một con trỏ đến một mảng (tức là, nó sẽ là con trỏ kiểu mà mảng sẽ phân hủy thành) và phần int của cặp sẽ là kích thước của mảng. Sau đó bạn có thể sử dụng nó như sau:

int array[10]; 
//...some code that initializes array, etc. 

cout << make_pair(array, 10); 

Một cộng với phương pháp này là nó cũng sẽ làm việc cho mảng động (ví dụ, mảng bạn phân bổ trên heap, vv)

+0

Tôi sẽ thử nó. Cảm ơn – Alcott

+0

Tôi có một cảm giác rất mờ nhạt rằng bạn có thể gặp rắc rối với ADL ở đây nếu 'T' của bạn không phải là loại do người dùng xác định, mặc dù tôi không thể chắc chắn. –

+0

Tôi đã thử nghiệm nó với một kiểu dựng sẵn như 'int' ... dường như hoạt động tốt ... Tôi không thể nghĩ tại sao điều này lại xung đột với các quy tắc ADL. Nếu bạn có đối tượng 'std :: pair ', mẫu phải có khả năng loại trừ loại 'T' và loại bỏ bất kỳ instantiations nào bằng cách sử dụng' std :: pair 'trong đó' U' không thuộc loại 'int' . – Jason

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