2013-04-16 57 views
8

Tôi đang cố triển khai lớp boolean của riêng mình, nhưng không thể sao chép ngữ nghĩa gốc cho & &. Mã giả tạo dưới đây trình bày vấn đề:Lười biếng, quá tải C++ && nhà điều hành?



    #include <iostream>> 

    class MyBool { 
    public: 
     bool theValue; 
     MyBool() {} 
     MyBool(bool aBool) {theValue = aBool;} 
     MyBool operator&& (MyBool aBool) {return theValue && aBool.theValue;} 
    }; 

    bool f1() {std::cout << " First\n"; return false;} 
    bool f2() {std::cout << " Second\n"; return false;} 

    int main(int argc, char** argv) { 
     std::cout << "Native &&\n"; 
     f1() && f2(); 
     std::cout << "Overloaded &&\n"; 
     MyBool(f1()) && MyBool(f2()); 
     return 0; 
} 

Khi biên dịch và chạy, kết quả là:

 

    Native && 
     First 
    Overloaded && 
     Second 
     First 

Nói cách khác, & & trên bools là lười biếng (như bất kỳ C++ lập trình viên mong đợi) nhưng quá tải & & không phải là (như lập trình C++ này ít nhất đã không mong đợi).

Có cách nào để quá tải & & không? Tôi có thể tìm thấy nhiều chương trình đánh giá đầy đủ về lười biếng để cung cấp chức năng giống như Haskell, nhưng chúng dường như hoàn toàn quá mức cần thiết cho trường hợp sử dụng của tôi.

+3

Bằng cách lười biếng, bạn có nghĩa là đoản mạch. Các toán tử bị quá tải không có mạch ngắn. – Rapptz

+0

Vấn đề này là chính xác lý do tại sao nó được khuyến khích không quá tải toán tử '&&'. –

+0

Lưu ý rằng lý do toán tử quá tải không thể đoản mạch là 'MyBool aBool' được truyền vào nó như một tham số. Vì vậy, 'MyBool (f2())' cần phải được tính toán trước khi thực hiện 'toán tử &' sẽ có cơ hội để chạy. Về lý thuyết, bạn có thể viết một toán tử 'operator &&' overload mà RHS là một hàm functor trả về 'MyBool'. Sau đó gọi functor đó chỉ khi LHS đánh giá đúng sự thật. Sau đó, trong C++ 11 người gọi có thể viết một lambda: 'MyBool (f1()) && []() {return MyBool (f2()); } '. Nhưng trong thực tế, không làm điều đó - đánh giá lười biếng là khá xấu xí khi bạn phải xác định rõ ràng nó trên mọi cuộc gọi. –

Trả lời

15

Bạn không nên quá tải bool operator&&, vì bạn mất đánh giá ngắn mạch, như bạn đã khám phá.

Cách tiếp cận đúng sẽ là để cung cấp cho lớp học của bạn chuyển đổi bool hành

class MyBool { 
public: 
    bool theValue; 
    MyBool() {} 
    MyBool(bool aBool) : theValue(aBool) {} 
    explicit operator bool() { return theValue; } 
}; 

Lưu ý rằng các nhà khai thác chuyển đổi rõ ràng đòi hỏi C++ 11 tuân thủ. Nếu bạn không có điều này, hãy xem safe bool idiom.

+2

+1 đây là chính xác (và cách duy nhất để thực sự làm điều đó) – Rapptz

+1

+1, nhưng cần lưu ý rằng 'toán tử rõ ràng là một tính năng C++ 11 và C++ 03 yêu cầu thành ngữ Bool Safe . – greyfade

+0

@greyfade Điểm tốt, tôi đã thêm một ghi chú. – juanchopanza

4

Có cách nào để quá tải & & không?

số

2

Bạn có thể làm hầu hết mọi thứ đánh giá một cách lười biếng với the expression template idiom, bao gồm nhưng không giới hạn ở các nhà khai thác có tích hợp sẵn trong các phiên bản ngắn mạch. Nhưng đó là công việc nhiều hơn bạn cần cho trường hợp này, kể từ đó lớp học MyBool của bạn sẽ yêu cầu thêm mã khác.

+0

"Bạn có thể thực hiện hầu hết mọi thứ đánh giá uể oải" - điều đó gây hiểu lầm, vì cách tiếp cận này chỉ hoạt động để hợp tác với các loại do người dùng xác định. Ví dụ, đối với bất kỳ 'T * p;' và 'myBool && ++ p', bạn không thể đoản mạch số gia tăng. –

0

Nếu bạn thực sự muốn đoản mạch và sẵn sàng hy sinh cú pháp điều hành, bạn có thể đổi tên phương pháp operator&& của bạn để _and, xác định một AND() vĩ mô, và viết AND(x,y) thay vì x&&y.

#define AND(x,y) (x._and(x.theValue ? y : MyBool(false))) 

Với một số macro hacks bạn có thể có AND() chấp nhận số lượng tham số thay đổi.

Phương pháp _and() ở đây không có ý định được sử dụng "công khai" ở đây nhưng phải được công khai vì bạn không thể friend một macro.

Đối với một cái gì đó đơn giản như lớp MyBool của bạn, điều này có lẽ không cần thiết. Nhưng nếu bạn cần operator&& để có các tác dụng phụ đặc biệt như cập nhật một số trạng thái trên this, thì việc này sẽ hoàn thành công việc.

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