การสร้างคอนสตรัคเตอร์ที่มีหลายอาร์กิวเมนต์explicitมีผล (มีประโยชน์) หรือไม่?
ตัวอย่าง:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
การสร้างคอนสตรัคเตอร์ที่มีหลายอาร์กิวเมนต์explicitมีผล (มีประโยชน์) หรือไม่?
ตัวอย่าง:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
คำตอบ:
จนถึง C ++ 11 ใช่ไม่มีเหตุผลที่จะใช้explicitกับตัวสร้างหลายอาร์กิวเมนต์
ที่เปลี่ยนแปลงใน C ++ 11 เนื่องจากรายการ initializer โดยพื้นฐานแล้วการเริ่มต้นการคัดลอก (แต่ไม่ใช่การเริ่มต้นโดยตรง) ด้วยรายการตัวเริ่มต้นจำเป็นต้องไม่ทำเครื่องหมายexplicitตัวสร้าง
ตัวอย่าง:
struct Foo { Foo(int, int); };
struct Bar { explicit Bar(int, int); };
Foo f1(1, 1); // ok
Foo f2 {1, 1}; // ok
Foo f3 = {1, 1}; // ok
Bar b1(1, 1); // ok
Bar b2 {1, 1}; // ok
Bar b3 = {1, 1}; // NOT OKAY
explicitแต่เป็นเพียงเพราะมันเป็นส่วนขยายของตรรกะของความหมายที่มีอยู่สำหรับ ฉันจะไม่รบกวนการสร้าง multi-arg constructor เป็นการexplicitส่วนตัว
คุณจะสะดุดกับการเริ่มต้นวงเล็บปีกกา (เช่นในอาร์เรย์)
struct A {
explicit A( int b, int c ) {}
};
struct B {
B( int b, int c ) {}
};
int main() {
B b[] = {{1,2}, {3,5}}; // OK
A a1[] = {A{1,2}, A{3,4}}; // OK
A a2[] = {{1,2}, {3,4}}; // Error
return 0;
}
คำตอบที่ยอดเยี่ยมโดย @StoryTeller และ @Sneftel คือเหตุผลหลัก อย่างไรก็ตาม IMHO นี่ก็สมเหตุสมผลแล้ว (อย่างน้อยฉันก็ทำ) เนื่องจากเป็นส่วนหนึ่งของการพิสูจน์อักษรในอนาคตจะเปลี่ยนรหัสในภายหลัง พิจารณาตัวอย่างของคุณ:
class A {
public:
explicit A( int b, int c );
};
explicitรหัสนี้ไม่ได้รับประโยชน์โดยตรงจาก
ในเวลาต่อมาคุณตัดสินใจที่จะเพิ่มค่าเริ่มต้นสำหรับcดังนั้นจึงกลายเป็นดังนี้:
class A {
public:
A( int b, int c=0 );
};
เมื่อทำเช่นนี้คุณกำลังมุ่งเน้นไปที่cพารามิเตอร์ - ในการมองย้อนกลับไปควรมีค่าเริ่มต้น คุณไม่จำเป็นต้องสนใจว่าAตัวเองควรถูกสร้างขึ้นโดยปริยายหรือไม่ ขออภัยการเปลี่ยนแปลงนี้ทำให้เกิดexplicitความเกี่ยวข้องอีกครั้ง
ดังนั้นเพื่อที่จะสื่อว่า ctor คือexplicitมันอาจต้องจ่ายเพื่อทำเช่นนั้นเมื่อเขียนวิธีการครั้งแรก
explicitที่อยู่ที่นั่นตลอดไปและฝ่ายสนับสนุนด้านเทคนิคจะได้รับการเรียกร้องเกี่ยวกับการเปลี่ยนแปลงนั้นและใช้เวลาหลายชั่วโมงในการอธิบายว่านั่นexplicitเป็นเพียงเสียงรบกวนและการลบออกนั้นไม่เป็นอันตราย โดยส่วนตัวแล้วฉันไม่ค่อยถนัดในการทำนายอนาคต ก็พอที่ยากที่จะตัดสินใจว่าอินเตอร์เฟซที่ควรมีลักษณะเช่นนี้
นี่คือห้าเซ็นต์ของฉันสำหรับการสนทนานี้:
struct Foo {
Foo(int, double) {}
};
struct Bar {
explicit Bar(int, double) {}
};
void foo(const Foo&) {}
void bar(const Bar&) {}
int main(int argc, char * argv[]) {
foo({ 42, 42.42 }); // valid
bar({ 42, 42.42 }); // invalid
return 0;
}
อย่างที่คุณเห็นได้อย่างง่ายดายexplicitป้องกันไม่ให้ใช้รายการเริ่มต้นควบคู่ไปกับbarฟังก์ชันเนื่องจากตัวสร้างของstruct Barถูกประกาศเป็นexplicit.