9

Tôi có một câu hỏi liên quan đến việc thành ngữ bool an toàn:const-đúng đắn và an toàn bool thành ngữ

typedef void (Testable::*bool_type)() const;    // const necessary? 
void this_type_does_not_support_comparisons() const {} // const necessary? 

operator bool_type() const 
{ 
    return ok_ ? &Testable::this_type_does_not_support_comparisons : 0; 
} 

Tại sao các bool_type (typedef) và this_type_does_not_support_comparisonsconst? Không ai thực sự phải gọi gọi chức năng thành viên thông qua con trỏ trả về, đúng không? Có phải const cần thiết ở đây không? operator bool_type (chức năng thành viên) có vi phạm chính xác không?

+0

đặt cược của tôi là 'const' là không cần thiết. Một cơ thể cho hàm này cũng không phải là vì bạn không phải gọi hàm đó. –

+0

@ Alex: Nhưng chức năng thành viên không có thân thể không có địa chỉ, đúng không? Nó không biên dịch mà không có một cơ thể trên VC10, ít nhất. – fredoverflow

+0

hmm bạn nói đúng. Tôi chỉ kiểm tra mẫu 'safe_bool' của mình mà tôi có trong dự án hiện tại của VS2010 và nó có phần thân. Nó cũng có 'const'. –

Trả lời

5

"Thành ngữ bool an toàn" là câu trả lời kỹ thuật cho câu hỏi "tôi muốn một chiếc xe vừa là xe thể thao vừa là máy kéo và có thể là thuyền". Câu trả lời thực tế không phải là câu trả lời kỹ thuật & hellip;

Điều đó nói rằng, vấn đề mà nó giải quyết chỉ là đưa ra kết quả có thể chuyển đổi thành bool nhưng không được nhiều thứ khác (nếu không, một thể hiện của lớp có thể được chuyển thành đối số thực tế, ví dụ: đối số chính thức là int, Nói). Một con trỏ dữ liệu có thể được chuyển đổi thành void*. Một con trỏ hàm không phải là, ít nhất là chính thức trong tiêu chuẩn C++ (Posix là cái gì khác, thực hành cũng).

Sử dụng con trỏ hàm thành viên bảo vệ chống lại việc vô tình gọi hàm, được cung cấp con trỏ từ toán tử bool an toàn. Các const hạn chế nó một chút, nhưng nếu số phận đã đặt một ai đó trên con đường làm cho số lượng tối đa của những sai lầm ngớ ngẩn, người đó vẫn có thể quản lý để gọi chức năng không làm gì cả. Thay vì const Tôi nghĩ rằng tôi sẽ chỉ để cho nó có một đối số của một loại tư nhân, nơi mà mã khác không thể cung cấp một đối số như vậy, và sau đó nó không phải là một loại hàm thành viên ngớ ngẩn nữa.

có thể trông như thế này:

#include <stdio.h> 

class Foo 
{ 
private: 
    enum PrivateArg {}; 
    typedef void (*SafeBool)(PrivateArg); 
    static void safeTrue(PrivateArg) {} 

    bool state_; 

public: 
    Foo(bool state): state_(state) {} 

    operator SafeBool() const 
    { return (state_? &safeTrue : 0); } 
}; 

int main() 
{ 
    if(Foo(true)) { printf("true\n"); } 
    if(Foo(false)) { printf("false\n"); } // No output. 

    //int const x1 = Foo(false);  // No compilado! 
    //void* const x2 = Foo(false);  // No compilado! 
} 

Tất nhiên, câu trả lời thực tế thay vì là một cái gì đó như thế này:

#include <stdio.h> 

class Foo 
{ 
private: 
    bool isEmpty_; 

public: 
    Foo(bool asInitiallyEmpty) 
     : isEmpty_(asInitiallyEmpty) 
    {} 

    bool isEmpty() const { return isEmpty_; } 
}; 

int main() 
{ 
    if(Foo(true).isEmpty()) { printf("true\n"); } 
    if(Foo(false).isEmpty()) { printf("false\n"); } // No output. 

    //bool const x0 = Foo(false);  // No compilado! 
    //int const x1 = Foo(false);  // No compilado! 
    //void* const x2 = Foo(false);  // No compilado! 
} 

Tóm tắt wrt. câu hỏi được yêu cầu:

  • Cách bool_type (typedef) và this_type_does_not_support_comparisons là const?

Ai đó không hiểu những gì họ đã mã hóa. Hoặc có thể là họ có ý định hạn chế khả năng gọi điện một chút. Nhưng sau đó, biện pháp khá vô ích.

  • Không ai thực sự phải gọi hàm thành viên thông qua con trỏ trả về, đúng không?

Phải.

  • Có cần thiết ở đây không?

số

  • Would hành bool_type (chức năng thành viên) vi phạm const-đúng đắn bằng cách khác?

số

Cheers & h.,

+0

"Tôi nghĩ rằng tôi sẽ để cho nó có một đối số của một loại tư nhân", oh chờ đợi, tôi rút lại tuyên bố trước đây của tôi, điều này là rực rỡ! – fredoverflow

+0

Tôi đã viết một cái gì đó sai về 'const', bằng cách nào đó gây nhầm lẫn màu đen và trắng. Tôi chỉ tấn công nó. Xin lỗi - phần còn lại là OK. –

+0

Bạn vẫn có thể (ngớ ngẩn, nhưng đây là điểm của bài tập) khai báo một hàm miễn phí với chữ ký 'void (Foo :: PrivateArg)' và so sánh nó với kết quả của 'toán tử SafeBool'. Tôi nghĩ kiểu 'SafeBool' phải là con trỏ tới hàm thành viên. –

1

8.3.5/A cv-vòng-seq sẽ chỉ là một phần của các loại chức năng cho một chức năng không tĩnh thành viên, các loại chức năng mà một con trỏ đến thành viên đề cập, hoặc loại chức năng cấp cao nhất của một hàm typedef khai báo. Ảnh hưởng của cv-qualifier-seq trong một khai báo hàm không giống như thêm cv-qualification trên đầu trang của hàm , nghĩa là, nó không tạo ra một loại hàm đủ điều kiện cv.

Nếu tôi đọc chính xác, bạn có thể trả về con trỏ tới thành viên không phải thành viên trong hàm thành viên const. Bạn sẽ không thể gọi nó với một đối tượng không const.

Một cách để ngăn cấm sự kêu gọi là:

private: 
    struct private_ 
    { 
     void this_type_does_not_support_comparisons() {} 
    }; 

public: 
    typedef void (private_::*bool_type)() const; 

    operator bool_type() const 
    { 
     return ok_ ? &private_::this_type_does_not_support_comparisons : 0; 
    } 

Con trỏ trỏ tới hàm thành viên vẫn có thể được so sánh với bình đẳng. Bạn phải viết một số operator==operator!= cho các loại Testable::bool_type kích hoạt lỗi. Dễ dàng hơn với dạng CRTP của thành ngữ bool an toàn vì các toán tử đó trở thành các khuôn mẫu và do đó có thể có một cơ thể sai.

Ví dụ:

template <typename T> 
class safe_bool_concept 
{ 
    // Implementation detail of safe bool 
protected: 
    ~safe_bool_concept() {} 

public: 
    operator safe_bool() const 
    { 
     return static_cast<const T*>(this)->is_null() ? ...; 
    } 
}; 

struct Foo : safe_bool_concept<Foo> 
{ 
    ... 

private: 
    friend class safe_bool_concept<Foo>; 
    bool is_null() const { ... } 
}; 

sau đó bạn có thể làm (làm tương tự với !=):

template <typename T> 
void operator==(const safe_bool_concept<T>& x, const safe_bool_concept<T>&) 
{ 
    x.some_private_member(); // invalid, but won't be generated 
          // unless safe_bool classes are compared 
} 

Điều này có nghĩa rằng bool thành ngữ an toàn nên được thực hiện thông qua CRTP nếu bạn muốn cấm so sánh . So sánh với số không sẽ vẫn làm việc tuy nhiên.

Nếu bạn đi theo tuyến đường chức năng không phải thành viên, bạn cũng sẽ phải cung cấp <, >, <=>=.

+0

@Alf: hãy để tôi viết một số mã, để ý định của tôi rõ ràng hơn. –

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