7

Hãy xem xét các nhà thầu sau đây cho T:Vấn đề với thứ tự độ phân giải constructor

struct T { 
    T(const bool) { std::cout << "T(const bool)" << endl; } 
    T(const std::string&) { std::cout << "T(const std::string&)" << endl; } 
}; 

T t(""); 
  1. Tại sao T(const bool) được ưu tiên hơn T(const std::string&) khi xây dựng t?
  2. Vì quyền ưu tiên trên có thể gây nhầm lẫn cho người dùng mong đợi T(const std::string&) được gọi, tôi có thể làm gì để có được T(const std::string&) được gọi ngầm khi truyền chuỗi ký tự cho hàm khởi tạo T. Hiện tại, công việc duy nhất tôi tìm thấy là thêm một nhà xây dựng, trong đó có ưu tiên cao nhất:

    T(const char* s) 
    { 
        std::cout << "T(const char*)" << endl; 
        *this = std::string(s); 
    } 
    
  3. Ngoài các giải pháp trên, tuyên bố explicit T(const bool) để tránh nhầm lẫn không giải quyết được vấn đề trên: trong trường hợp này, mặc dù T t = "" hiện đang bị cấm, tại sao là hình thức T t("") vẫn được phép và gọi T(const bool)?

Trả lời

8

Tại sao T(const bool) được ưu tiên hơn T(const std::string&) khi xây dựng t?

"" thuộc loại char[1]; điều này được chuyển đổi hoàn toàn thành char const* thông qua chuyển đổi mảng-thành-con trỏ. Một con trỏ được chuyển đổi hoàn toàn thành bool, với tất cả các con trỏ không null trở thành true và tất cả các con trỏ null trở thành false. Đây là cả hai chuyển đổi chuẩn "được tích hợp sẵn".

Chuyển đổi char const* -> std::string là chuyển đổi do người dùng khai báo: nó sử dụng một hàm tạo chuyển đổi là std::string có số char const*.

Chuyển đổi tiêu chuẩn ("được tích hợp") được ưu tiên hơn chuyển đổi do người dùng khai báo trong quá trình phân giải quá tải, do đó nhà xây dựng lấy bool là kết hợp tốt hơn so với số std::string.

Còn bây giờ công việc duy nhất xung quanh tôi đã tìm thấy là thêm constructor khác

Đó có vẻ là một giải pháp hợp lý; chắc chắn là giải pháp đơn giản nhất cho kịch bản đơn giản mà bạn mô tả. Tuy nhiên, việc sử dụng bài tập của bạn cho *this hơi vụng về; nó sẽ là tốt hơn hoặc để có cả hai nhà thầu đại biểu cho một số chức năng khởi tạo.

Ngoài ra, bạn có thể sử dụng một mẫu với enable_if đối với bất kỳ nhà xây dựng mà bạn muốn không cho phép chuyển đổi:

template <typename U> 
T(U, std::enable_if<std::is_same<U, bool>::value>::type* = 0) { } 

constructor này sẽ chỉ có thể được gọi với một đối số bool và không có gì khác. Bạn có thể tìm thấy enable_ifis_same trong Boost, C++ TR1 hoặc C++ 0x. Bạn cũng có thể sử dụng !is_pointer, is_integral hoặc một số kết hợp loại đặc điểm khác để cho phép đối với một số loại đối số khác chứ không phải char const*.

Hoặc, như một giải pháp thay thế khác, bạn có thể tránh hoàn toàn bool và sử dụng điều tra của riêng bạn với các điều tra viên tương ứng với truefalse cho hàm tạo. Cho dù điều này có ý nghĩa hay không tùy thuộc vào trường hợp sử dụng của bạn.

Tuyên bố explicit T(const bool) để tránh không giải quyết được vấn đề trên ... tại sao biểu mẫu T t("") vẫn được phép và gọi T(const bool)?

explicit chỉ không cho phép chuyển đổi ẩn thành T. T t(""); không có chuyển đổi nào đối với T; nó trực tiếp khởi tạo đối tượng t bằng cách xây dựng nó với đối số "" được truyền cho bất kỳ hàm tạo nào phù hợp nhất.

+0

cảm ơn nhiều giải pháp với Mẫu – pipex

+0

'enable_if' sẽ kết thúc bằng' ... :: type * = 0'. – UncleBens

+0

@UncleBens: Rất cám ơn. Đã sửa. –

1

"" có thể chuyển đổi thành cả hai số std::stringbool.

Câu hỏi đặt ra là, theo cách nào nó sẽ chuyển đổi?

  • Chuyển đổi thành std::string là chuyển đổi do người dùng xác định.
  • Chuyển đổi thành bool là chuyển đổi chuẩn.

Vì vậy, câu trả lời là, chuyển đổi chuẩn có ưu tiên cao hơn chuyển đổi do người dùng xác định. Vì vậy, "" sẽ chuyển đổi thành bool.

Ví dụ,

struct A 
{ 
    A(int i) {} //i.e an int can implicity convert to A 
}; 

void f(const A &) { cout << "User-defined conversion won" << endl; } 
void f(const bool &) { cout << "Standard conversion won" << endl; } 

int main() { 
     f (10); 
     return 0; 
} 

Output:

Standard conversion won 

bản demo online: http://www.ideone.com/5Bt0K

Trong bản demo trên, 10 có thể chuyển đổi sang Abool cả hai. Kể từ khi chuyển đổi sang bool là chuyển đổi chuẩn, nó chuyển đổi thành bool, thay vì A.

0

Do chuyển đổi do người dùng xác định không được xem xét nếu có sẵn một chuyển đổi tích hợp sẵn.

Sử dụng hàm tạo thứ ba, hàm tạo const char*. Không có cách nào tốt hơn.

+0

"Không có cách nào tốt hơn." Tôi có ý kiến ​​khác. –

+0

@James McNellis: Phương pháp của bạn với 'enable_if' trông rất đẹp. –

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