2016-09-20 17 views
7

Trong ví dụ sau, đầu ra của tôi là "ctor param duy nhất", hai lần. Câu hỏi của tôi là gấp đôi, đầu tiên, tại sao là bool ctor được gọi là thay vì phiên bản có chứa chuỗi, và thứ hai, là có một cách để có được phiên bản chuỗi được gọi mà không cần gọi các cuộc gọi?constructor rõ ràng của loại sai gọi là

Là một sang một bên, mã thực tế của tôi không gọi các nhà thầu với chuỗi mã hóa cứng nhưng với một cái gì đó như:

static constexpr auto NONE = "NONE"; 
Foo aFoo(NONE); 

...

#include <iostream> 
#include <string> 

using namespace std; 


struct Foo { 

    explicit Foo(bool _isVisible = false): id(""), isVisible(_isVisible) {cout << "single param ctor" << endl;} 
    explicit Foo(const string _id, bool _isVisible = false): id(_id), isVisible(_isVisible) {cout << "multip param ctor" << endl;} 

    const string id; 
    bool isVisible; 
}; 

int main(int argc, const char * argv[]) { 

    shared_ptr<Foo> sharedFoo = make_shared<Foo>("hello"); 
    Foo regFoo("hi"); 
    return 0; 
} 

Trả lời

8

Đây là một hạn chế của C++ được kế thừa từ cũ hơn C++ và cuối cùng từ C.

Chuỗi ký tự chuỗi của bạn chuyển thành bool tốt hơn so với loại "do người dùng xác định" std::string.

Thay vì đúc trong cuộc gọi, bạn có thể thêm một constructor mà mất const char*, có thể có nó uỷ thác cho nhà xây dựng hiện tại của bạn mà có std::string:

explicit Foo(const char* _id, bool _isVisible = false) 
    : Foo(std::string(_id), _isVisible) 
{}; 

constructor Đây sẽ là một "kết hợp chính xác" (hoặc đóng đủ anyway) và ngăn chặn bool từ ăn cắp ánh đèn sân khấu.

Hoặc, vì C++ 14, thay vì sử dụng dàn diễn viên the std::string literal, ví dụ: "hi"s, mặc dù bạn phải nhớ thực hiện điều này tại các cuộc gọi mà là một chút "meh" cho một giải pháp chung.

Bằng cách này, nếu bạn thực sự muốn tham số std::string _id theo giá trị, không được đặt là const; bạn đang ngăn không cho nó bị dịch chuyển và yêu cầu một bản sao trong bộ khởi tạo thành viên. Tùy thuộc vào những gì đang xảy ra tại callsite điển hình của bạn, sau đây có thể làm cho ý nghĩa hơn:

explicit Foo(
    string _id, 
    bool _isVisible = false 
) 
    : id(std::move(_id)) 
    , isVisible(_isVisible) 
{} 

Nếu bạn thường vượt qua trong một giá trị trái, tuy nhiên, ít nhất là chấp nhận một const std::string& để ngăn chặn một bản sao.

+0

nên không vô nghĩa như mong muốn này tiềm ẩn * string-đen * để * bool * chuyển đổi có ưu tiên cao hơn không được chấp nhận trong C + +? – WhiZTiM

+0

@WhiZTiM: 'nullptr' được giới thiệu để trợ giúp trong một số trường hợp nhưng, trừ khi chúng ta thay đổi loại chuỗi ký tự, hoặc loại bỏ mảng-tên-phân rã, hoặc thay đổi cách con trỏ hoạt động, chúng ta đang mắc kẹt với nó. Vì vậy, ''foo' s' sau đó được giới thiệu để cung cấp cho chúng ta các chuỗi ký tự không chống lại vấn đề .. nhưng điều đó chỉ hữu ích khi bạn đã biết được vấn đề! Và nếu bạn đang có, sau đó nó tương đối dễ dàng giải quyết tại nguồn anyway (như được hiển thị ở trên). –

+0

@WhiZTiM: BTW từ bạn đang tìm kiếm là "không được chấp nhận". –

0

tại sao ctor bool gọi chứ không phải là phiên bản chứa chuỗi

"hi" một con trỏ đến char một loạt các ký tự được chuyển đổi thành một con trỏ đến char (nhờ, Lightness Races trong Orbit), do đó, một số, mà tôi chuyển đổi thành một bool.

có cách nào để nhận phiên bản chuỗi được gọi mà không cần thực hiện cuộc gọi không?

Không thực sự tao nhã, nhưng ... bạn có thể vượt qua một boolean param thứ hai

Foo regFoo("hi", false); 

để loại trừ các nhà xây dựng đầu tiên

+1

'" hi "' là một mảng char, nhưng kiểu của biểu thức sẽ phân rã thành con trỏ tới char khá nhanh –

+0

@LightnessRacesinOrbit - thanks; sửa chữa – max66

+0

Hoặc làm cho nó một std thực :: string literal trong C++ 14: 'Foo regFoo (" hi "s);' –

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