2008-12-03 33 views
18

Giả sử có một hàm mẫu trong C++ thực hiện một số công việc hữu ích nhưng cũng xuất ra một chuỗi các giá trị thông qua trình lặp đầu ra. Bây giờ giả sử rằng chuỗi giá trị đôi khi là thú vị, nhưng ở những giá trị khác thì không hữu ích. Có một lớp iterator sẵn sàng sử dụng trong STL có thể được khởi tạo và chuyển tới hàm và sẽ bỏ qua bất kỳ giá trị nào mà hàm cố gắng gán cho trình vòng lặp đầu ra không? Nói cách khác, gửi tất cả dữ liệu đến/dev/null?Loại bỏ đầu ra của một hàm cần trình lặp đầu ra

Trả lời

3

Bạn có Tăng cường khả dụng không? Nếu vậy, bạn có thể sử dụng một hàm function_output_iterator gói một hàm trống.

Nó không phải là lý tưởng mặc dù. Bất kỳ trình lặp nào bạn sử dụng sẽ vẫn cần phải tạo một cá thể của value_type để trả về toán tử *, ngay cả khi nó ném nó đi.

4

Không khó để viết một.

template<typename T> 
class NullOutputIterator 
{ 
public: 
    NullOutputIterator() {} 
    NullOutputIterator& operator++() { return *this; } 
    NullOutputIterator& operator++(int) { return *this; } 
    T& operator*() { return m; } 
    T* operator->() { return &m; } 
private: 
    T m; 
}; 

Tôi chưa thử nghiệm điều này và có thể có điều gì đó quan trọng bị thiếu, nhưng tôi nghĩ đây là ý tưởng.

+1

Ý tưởng là tốt, nhưng tôi không nghĩ bạn cần: toán tử T * ->() {return & m; } Và bạn nên bắt nguồn từ stl :: output_iterator Với việc triển khai này, một bản sao của T được thực hiện tại mỗi nhiệm vụ thông qua trình lặp ra ngoài. Có cách nào để tránh điều đó không? –

20

STL không cung cấp trình lặp đó. Nhưng bạn có thể tự viết mã (thử nghiệm mã đó):

struct null_output_iterator : 
    std::iterator< std::output_iterator_tag, 
        null_output_iterator > { 
    /* no-op assignment */ 
    template<typename T> 
    void operator=(T const&) { } 

    null_output_iterator & operator++() { 
     return *this; 
    } 

    null_output_iterator operator++(int) { 
     return *this; 
    } 

    null_output_iterator & operator*() { return *this; } 
}; 

Không cần bất kỳ dữ liệu nào do sử dụng kết quả là operator*. Kết quả của *it = x; không được sử dụng trong các yêu cầu của trình lặp đầu ra, vì vậy chúng tôi có thể cung cấp cho nó kiểu trả về là void.


Chỉnh sửa: Hãy xem cách hoạt động của operator*. Tiêu chuẩn nói trong 24.1.2/1 về các yêu cầu của một iterator đầu ra rằng trong cả hai trường hợp này:

*it = t; 
*it++ = t; 

Đó là kết quả của những biểu hiện không được sử dụng. Đó là những gì làm cho công việc này:

null_output_iterator it; 
*it; // returns a null_output_iterator& per definition of the `operator*`. 
*it = some_value; // returns void per definition of the templated `operator=`. 

Bây giờ chúng ta không cần phải có bất kỳ dữ liệu mà chúng tôi quay trở lại trong operator*: Chúng tôi chỉ cần sử dụng iterator riêng của mình. Lưu ý rằng toán tử templated = không ghi đè toán tử gán bản sao được tạo sẵn. Nó vẫn được cung cấp.

+0

Bạn có thể giải thích rõ hơn toán tử *? –

+0

Nó được sử dụng kết hợp với toán tử templated =. Tricky, tôi sẽ sử dụng một lớp helper lồng nhau dev_null. Ngoài ra, tôi cho phép toán tử ++ (int) trả về * điều này ngay lập tức. Phiên bản này không hiệu quả. – MSalters

+0

msalters, trạng thái ngữ nghĩa hoạt động của một đối tượng mới được trả về :) –

0

tôi dựa trên mỏ std::back_insert_iterator, nhưng không có container:

#include <iterator> 

template<typename T> 
class NullOutputIter 
    : public std::iterator<std::output_iterator_tag,void,void,void,void> 
{ 
public: 
    NullOutputIter &operator=(const T &) { return *this; } 
    NullOutputIter &operator*() { return *this; } 
    NullOutputIter &operator++() { return *this; } 
    NullOutputIter operator++(int) { return *this; } 
}; 

này cũng tương tự như câu trả lời của Johannes, nhưng không có mẫu operator= rằng phải mất bất cứ điều gì. Tôi thích gõ mạnh; Tôi muốn *it = wrong_type_thing là lỗi biên dịch. Điều này cũng sử dụng void cho các tham số mẫu khác nhau cho std::iterator, giống như các trình vòng lặp đầu ra trong thư viện chuẩn.

Điều này cũng tương tự như giải pháp của Mark, nhưng (a) nó thừa hưởng chính xác từ std::iterator và (b) nó không có biến trạng thái nội bộ không cần thiết.

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