การเริ่มต้นโครงสร้าง C ++


279

เป็นไปได้ที่จะเริ่มต้น structs ใน C ++ ตามที่ระบุไว้ด้านล่าง

struct address {
    int street_no;
    char *street_name;
    char *city;
    char *prov;
    char *postal_code;
};
address temp_address =
    { .city = "Hamilton", .prov = "Ontario" };

ลิงก์ที่นี่และที่นี่พูดถึงว่าเป็นไปได้ที่จะใช้สไตล์นี้เฉพาะใน C เท่านั้นถ้าเป็นเช่นนั้นทำไมจึงไม่สามารถใช้ C ++ ได้? มีเหตุผลทางเทคนิคที่แฝงอยู่หรือไม่ว่าทำไมมันจึงไม่ถูกนำไปใช้ใน C ++ หรือเป็นวิธีปฏิบัติที่ไม่ดีที่จะใช้สไตล์นี้ ฉันชอบใช้วิธีการเริ่มต้นนี้เนื่องจากโครงสร้างของฉันมีขนาดใหญ่และรูปแบบนี้ทำให้ฉันสามารถอ่านได้อย่างชัดเจนว่าค่าใดถูกกำหนดให้กับสมาชิกคนใด

กรุณาแบ่งปันกับฉันหากมีวิธีอื่น ๆ ที่เราสามารถบรรลุการอ่านเดียวกัน

ฉันได้อ้างอิงลิงค์ต่อไปนี้ก่อนโพสต์คำถามนี้

  1. C / C ++ สำหรับ AIX
  2. โครงสร้างเริ่มต้น C กับตัวแปร
  3. เริ่มต้นโครงสร้างคงที่ด้วยแท็กใน C ++
  4. C ++ 11 การเริ่มต้นโครงสร้างที่เหมาะสม

20
มุมมองส่วนบุคคลของโลก: คุณไม่จำเป็นต้องใช้รูปแบบของการเริ่มต้นวัตถุใน C ++ เพราะคุณควรใช้ Constructor แทน
ฟิลิปเคนดัลล์

7
ใช่ฉันคิดอย่างนั้น แต่ฉันมีโครงสร้างขนาดใหญ่มากมาย มันจะง่ายและอ่านได้สำหรับฉันที่จะใช้วิธีนี้ คุณมีสไตล์ / แนวปฏิบัติที่ดีในการเริ่มต้นใช้ Constructor ซึ่งให้การอ่านที่ดีขึ้นเช่นกัน
Dinesh PR

2
คุณเคยพิจารณาห้องสมุดเพิ่มพารามิเตอร์ร่วมกับตัวสร้าง? boost.org/doc/libs/1_50_0/libs/parameter/doc/html/index.html
Tony Delroy

18
ไม่เกี่ยวข้องกับการเขียนโปรแกรม: ที่อยู่นี้ใช้ได้ดีในสหรัฐอเมริกาเท่านั้น ในประเทศฝรั่งเศสเราไม่มี "จังหวัด" ในส่วนอื่น ๆ ของโลกไม่มีรหัสไปรษณีย์คุณย่าของเพื่อนอาศัยอยู่ในหมู่บ้านเล็ก ๆ แห่งหนึ่งที่อยู่ของเธอคือ "Ms X, รหัสไปรษณีย์ ชื่อหมู่บ้านเล็ก ๆ "(อ๋อไม่มีถนน) ดังนั้นให้พิจารณาอย่างรอบคอบว่าที่อยู่ที่ถูกต้องคืออะไรสำหรับตลาดที่คุณจะนำไปใช้กับ);
Matthieu M.

5
@MatthieuM ไม่มีจังหวัดใดในสหรัฐอเมริกา (อาจเป็นรูปแบบของแคนาดาใช่ไหม) แต่มีรัฐดินแดนและแม้แต่หมู่บ้านเล็ก ๆ ที่ไม่ใส่ใจกับชื่อถนน ดังนั้นประเด็นเรื่องความสอดคล้องของที่อยู่จึงมีผลแม้ที่นี่
ทิม

คำตอบ:


166

หากคุณต้องการทำให้ชัดเจนว่าแต่ละค่าเริ่มต้นคือเพียงแยกมันในหลายบรรทัดด้วยความคิดเห็นในแต่ละ:

address temp_addres = {
  0,  // street_no
  nullptr,  // street_name
  "Hamilton",  // city
  "Ontario",  // prov
  nullptr,  // postal_code
};

7
ฉันชอบและแนะนำสไตล์นี้เป็นการส่วนตัว
Dinesh PR

30
อะไรคือความแตกต่างระหว่างการทำเช่นนั้นกับการใช้เครื่องหมายจุดเพื่อเข้าถึงฟิลด์ได้อย่างแม่นยำมากขึ้นมันไม่เหมือนกับที่คุณประหยัดพื้นที่ใด ๆ ถ้านั่นคือสิ่งที่เป็นข้อกังวล ฉันไม่ได้รับโปรแกรมเมอร์ C ++ จริงๆเมื่อพูดถึงความสอดคล้องและการเขียนโค้ดที่สามารถบำรุงรักษาได้ดูเหมือนว่าพวกเขาต้องการทำสิ่งที่แตกต่างออกไปเพื่อทำให้รหัสของพวกเขาโดดเด่นอยู่เสมอ สำนวนของตัวเองมีจุดมุ่งหมายเพื่อความน่าเชื่อถือและความง่ายในการบำรุงรักษา

5
@ user1043000 ดีสำหรับหนึ่งในกรณีนี้ลำดับที่คุณทำให้สมาชิกของคุณมีความสำคัญสูงสุด หากคุณเพิ่มเขตข้อมูลที่อยู่ตรงกลางโครงสร้างของคุณคุณจะต้องกลับไปที่รหัสนี้และมองหาจุดที่แน่นอนที่จะแทรกการเริ่มต้นใหม่ของคุณซึ่งยากและน่าเบื่อ ด้วยเครื่องหมายจุดคุณสามารถกำหนดค่าเริ่มต้นใหม่ของคุณไว้ที่ท้ายรายการโดยไม่รบกวนคำสั่ง และจุดสัญกรณ์เป็นวิธีที่ปลอดภัยยิ่งขึ้นถ้าคุณเพิ่มประเภทเดียวกัน (เช่นchar*) ในฐานะสมาชิกคนหนึ่งของสมาชิกด้านบนหรือด้านล่างในโครงสร้างเนื่องจากไม่มีความเสี่ยงในการแลกเปลี่ยน
Gui13

6
ความคิดเห็นของ orip หากคำจำกัดความของโครงสร้างข้อมูลมีการเปลี่ยนแปลงและไม่มีใครคิดที่จะมองหาการเริ่มต้นหรือไม่สามารถหาพวกเขาทั้งหมดหรือทำให้การแก้ไขพวกเขาผิดพลาดสิ่งต่าง ๆ จะแตกสลาย
Edward Falk

3
ส่วนใหญ่ (ถ้าไม่ทั้งหมด) POSIX structs ไม่มีคำสั่งที่กำหนดไว้เฉพาะสมาชิกที่กำหนดไว้ (struct timeval){ .seconds = 0, .microseconds = 100 }จะเป็นมิลลิร้อย แต่timeval { 0, 100 }อาจจะเป็นร้อยวินาที คุณไม่ต้องการที่จะหาสิ่งที่ยากออก
yyny

99

หลังจากที่คำถามของฉันไม่มีผลลัพธ์ที่น่าพึงพอใจ (เนื่องจาก C ++ ไม่ได้ใช้ init ตามแท็กสำหรับโครงสร้าง) ฉันใช้เคล็ดลับที่พบที่นี่: สมาชิกของโครงสร้าง C ++ เริ่มต้นเป็น 0 ตามค่าเริ่มต้นหรือไม่

สำหรับคุณมันเป็นจำนวนเงินที่จะทำเช่นนั้น:

address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";

นี่เป็นสิ่งที่ใกล้เคียงที่สุดกับสิ่งที่คุณต้องการในตอนแรก (เป็นศูนย์ทุกฟิลด์ยกเว้นที่คุณต้องการเริ่มต้น)


10
สิ่งนี้ไม่สามารถใช้ได้กับวัตถุที่ไม่ได้ตั้งใจแบบคงที่
user877329

5
static address temp_address = {};จะทำงาน. การเติมมันหลังจากนั้นขึ้นอยู่กับรันไทม์ใช่ คุณสามารถหลีกเลี่ยงนี้โดยการให้ฟังก์ชั่นแบบคงที่ไม่ init static address temp_address = init_my_temp_address();สำหรับคุณ:
Gui13

ใน C ++ 11 init_my_temp_addressสามารถเป็นฟังก์ชัน lambda:static address temp_address = [] () { /* initialization code */ }();
dureuill

3
ความคิดที่ไม่ดีมันละเมิดหลักการ RAII
hxpax

2
แนวคิดที่ไม่ดีจริง ๆ : เพิ่มสมาชิกหนึ่งคนในของคุณaddressและคุณจะไม่เคยรู้สถานที่ทั้งหมดที่สร้างaddressและตอนนี้จะไม่เริ่มต้นสมาชิกใหม่ของคุณ
ลึกลับ_doctor

25

ตามที่คนอื่นได้กล่าวมานี้เป็นเครื่องมือเริ่มต้นที่กำหนด

คุณลักษณะนี้เป็นส่วนหนึ่งของC ++ 20


17

ตัวระบุฟิลด์เป็นไวยากรณ์เริ่มต้นของ C ใน C ++ เพียงแค่ให้ค่าในลำดับที่ถูกต้องโดยไม่มีชื่อเขตข้อมูล น่าเสียดายที่นี่หมายความว่าคุณต้องให้ทั้งหมด (จริง ๆ แล้วคุณสามารถละเว้นเขตข้อมูลที่มีค่าเป็นศูนย์ต่อท้ายและผลลัพธ์จะเหมือนกัน):

address temp_address = { 0, 0, "Hamilton", "Ontario", 0 }; 

1
ใช่คุณสามารถใช้การกำหนดค่าเริ่มต้น struct
texasbruce

3
ใช่ปัจจุบันฉันใช้วิธีนี้เท่านั้น (การจัดโครงสร้างเริ่มต้นที่สอดคล้อง) แต่ฉันรู้สึกว่าการอ่านไม่ดี เนื่องจากโครงสร้างของฉันมีขนาดใหญ่ initializer จึงมีข้อมูลจำนวนมากและมันเป็นเรื่องยากสำหรับฉันที่จะติดตามว่าค่าใดถูกกำหนดให้กับสมาชิกคนใด
Dinesh PR

7
@ DineshP.R จากนั้นเขียนตัวสร้าง!
นาย Lister

2
@MrLister (หรือใครก็ได้) บางทีฉันอาจติดอยู่ในกลุ่มเมฆของความโง่เขลาในขณะนี้ แต่สนใจที่จะอธิบายว่านวกรรมิกจะดีกว่ามากแค่ไหน? ดูเหมือนว่าฉันมีความแตกต่างกันเล็กน้อยระหว่างการให้ค่าที่ไม่มีชื่อตามคำสั่งจำนวนมากกับรายการเริ่มต้นหรือให้ค่าที่ไม่มีชื่อตามคำสั่งจำนวนมากแก่ผู้สร้าง ...
yano

1
@yano บอกตามตรงฉันไม่จำได้ว่าทำไมฉันถึงคิดว่าคอนสตรัคเตอร์จะเป็นคำตอบของปัญหา ถ้าฉันจำได้ฉันจะกลับมาหาคุณ
นาย Lister

13

คุณลักษณะนี้เรียกว่าinitializers กำหนด มันเป็นส่วนเสริมของมาตรฐาน C99 อย่างไรก็ตามคุณลักษณะนี้ถูกทิ้งไว้ใน C ++ 11 ตามภาษาการเขียนโปรแกรม C ++ รุ่นที่ 4 ส่วนที่ 44.3.3.2 (คุณสมบัติ C ที่ไม่ได้รับการรับรองจาก C ++):

มีการเพิ่มเติมบางส่วนใน C99 (เปรียบเทียบกับ C89) โดยไม่ได้นำมาใช้ใน C ++:

[1] อาร์เรย์ที่มีความยาวแปรผัน (VLAs) ใช้เวกเตอร์หรือไดนามิกอาร์เรย์บางรูปแบบ

[2] กำหนด initializers; ใช้ตัวสร้าง

ไวยากรณ์ C99 มีค่าเริ่มต้นที่กำหนด [ดู ISO / IEC 9899: 2011, ร่างคณะกรรมการ N1570 - 12 เมษายน 2011]

6.7.9 การเริ่มต้น

initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }
initializer-list:
    designation_opt initializer
    initializer-list , designationopt initializer
designation:
    designator-list =
designator-list:
    designator
    designator-list designator
designator:
    [ constant-expression ]
    . identifier

ในทางตรงกันข้าม C ++ 11 ไม่มีinitializers ที่กำหนด [ดู ISO / IEC 14882: 2011, ร่างคณะกรรมการ N3690 - 15 พฤษภาคม 2013]

8.5 Initializers

initializer:
    brace-or-equal-initializer
    ( expression-list )
brace-or-equal-initializer:
    = initializer-clause
    braced-init-list
initializer-clause:
    assignment-expression
    braced-init-list
initializer-list:
    initializer-clause ...opt
    initializer-list , initializer-clause ...opt
braced-init-list:
    { initializer-list ,opt }
    { }

เพื่อให้บรรลุผลที่เหมือนกันใช้ constructors หรือรายการ initializer:


9

คุณสามารถเริ่มต้นผ่าน ctor:

struct address {
  address() : city("Hamilton"), prov("Ontario") {}
  int street_no;
  char *street_name;
  char *city;
  char *prov;
  char *postal_code;
};

9
struct addressนี่เป็นกรณีเฉพาะในกรณีที่คุณสามารถควบคุมความหมายของ นอกจากนี้ชนิด POD มักจะไม่มีคอนสตรัคเตอร์และตัวทำลาย
4815162342

7

คุณยังสามารถบรรจุโซลูชันของ Gui13 ไว้ในคำสั่งเริ่มต้นเดียว:

struct address {
                 int street_no;
                 char *street_name;
                 char *city;
                 char *prov;
                 char *postal_code;
               };


address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);

คำเตือน: ฉันไม่แนะนำสไตล์นี้


สิ่งนี้ยังคงเป็นอันตรายเพราะช่วยให้คุณสามารถเพิ่มสมาชิกaddressและรหัสจะยังคงรวบรวมกับสถานที่นับล้านที่เริ่มต้นสมาชิกห้าเดิมเท่านั้น ส่วนที่ดีที่สุดของการเริ่มต้น struct คือคุณสามารถมีสมาชิกทั้งหมดconstและมันจะบังคับให้คุณเริ่มต้นพวกเขาทั้งหมด
ปริศนา _doctor

7

ฉันรู้ว่าคำถามนี้ค่อนข้างเก่า แต่ฉันพบวิธีการเริ่มต้นอีกวิธีหนึ่งโดยใช้ constexpr และ currying:

struct mp_struct_t {
    public:
        constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {}
        constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {}
        constexpr mp_struct_t another_member(int member) { return {member1, member,     member2}; }
        constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; }

    int member1, member2, member3;
};

static mp_struct_t a_struct = mp_struct_t{1}
                           .another_member(2)
                           .yet_another_one(3);

วิธีนี้ยังใช้ได้กับตัวแปรคงที่ทั่วโลกและแม้กระทั่ง constexpr ข้อเสียเพียงอย่างเดียวคือความสามารถในการบำรุงรักษาที่ไม่ดี: ทุกครั้งที่สมาชิกรายอื่นต้องทำการเริ่มต้นใหม่ได้โดยใช้วิธีนี้วิธีการเริ่มต้นสมาชิกทั้งหมดจะต้องเปลี่ยน


1
นี่คือรูปแบบการสร้าง เมธอดสมาชิกสามารถส่งคืนการอ้างอิงไปยังคุณสมบัติที่จะถูกแก้ไขแทนการสร้างโครงสร้างใหม่ทุกครั้ง
phuclv

6

ฉันอาจจะพลาดบางสิ่งบางอย่างที่นี่โดยทำไมไม่:

#include <cstdio>    
struct Group {
    int x;
    int y;
    const char* s;
};

int main() 
{  
  Group group {
    .x = 1, 
    .y = 2, 
    .s = "Hello it works"
  };
  printf("%d, %d, %s", group.x, group.y, group.s);
}

ฉันรวบรวมโปรแกรมข้างต้นด้วยคอมไพเลอร์ MinGW C ++ และคอมไพเลอร์ Arduino AVR C ++ และทั้งคู่ก็วิ่งตามที่คาดไว้ สังเกต #include <cstdio>
run_the_race

4
@run_the_race นี่เป็นเรื่องเกี่ยวกับสิ่งที่มาตรฐาน c ++ บอกว่าไม่ใช่พฤติกรรมของคอมไพเลอร์ที่กำหนด อย่างไรก็ตามคุณลักษณะนี้มาใน c ++ 20
Jon

ใช้งานได้เฉพาะถ้า struct คือ POD ดังนั้นมันจะหยุดรวบรวมถ้าคุณเพิ่มนวกรรมิก
oromoiluig

5

มันไม่ได้ใช้งานใน C ++ (ยังchar*สตริงหรือไม่ฉันหวังว่าไม่)

โดยปกติถ้าคุณมีพารามิเตอร์มากมายมันเป็นกลิ่นรหัสที่ค่อนข้างร้ายแรง แต่ทำไมไม่เพียงแค่กำหนดค่าเริ่มต้นโครงสร้างแล้วกำหนดสมาชิกแต่ละคน


6
"(เช่นกันchar*ใช่ไหมฉันหวังว่าไม่ได้)" - ก็เป็นตัวอย่าง C
เอ็ดเอส

เราใช้ char * ในภาษา C ++ ไม่ได้เหรอ? ขณะนี้ฉันกำลังใช้งานอยู่และมันใช้งานได้ (อาจเป็นเพราะฉันกำลังทำสิ่งที่ผิด) สมมติฐานของฉันคือคอมไพเลอร์จะสร้างสตริงคงที่ของ "แฮมิลตัน" และ "ออนตาริโอ" และกำหนดที่อยู่ของพวกเขาให้กับสมาชิก struct การใช้ const char * ถูกต้องหรือไม่
Dinesh PR

8
คุณสามารถใช้char*แต่const char*มีความปลอดภัยมากกว่าและทุกคนก็ใช้std::stringเพราะมีความน่าเชื่อถือมากกว่า
ลูกสุนัข

ตกลง. เมื่อฉันอ่าน "ตามที่ระบุไว้ด้านล่าง" ฉันคิดว่ามันเป็นตัวอย่างที่คัดลอกมาจากที่อื่น
Ed S.

2

ฉันพบวิธีนี้สำหรับตัวแปรทั่วโลกซึ่งไม่จำเป็นต้องแก้ไขนิยามโครงสร้างเดิม:

struct address {
             int street_no;
             char *street_name;
             char *city;
             char *prov;
             char *postal_code;
           };

จากนั้นประกาศตัวแปรประเภทใหม่ที่สืบทอดมาจากโครงสร้างดั้งเดิมและใช้ตัวสร้างสำหรับการเริ่มต้นฟิลด์:

struct temp_address : address { temp_address() { 
    city = "Hamilton"; 
    prov = "Ontario"; 
} } temp_address;

ไม่ค่อยหรูหราเท่าซีสไตล์ แต่ ...

สำหรับตัวแปรในท้องที่จะต้องมี memset เพิ่มเติม (นี่คือ 0, sizeof (* this)) ที่จุดเริ่มต้นของ Constructor ดังนั้นจึงไม่ชัดเจนและแย่กว่าและคำตอบของ @ gui13 เหมาะสมกว่า

(โปรดทราบว่า 'temp_address' เป็นตัวแปรประเภท 'temp_address' อย่างไรก็ตามประเภทใหม่นี้สืบทอดมาจาก 'ที่อยู่' และสามารถใช้งานได้ในทุกที่ที่คาดว่า 'ที่อยู่' จึงตกลง)


1

ฉันเผชิญกับปัญหาที่คล้ายกันในวันนี้ที่ฉันมีโครงสร้างที่ฉันต้องการกรอกข้อมูลการทดสอบซึ่งจะถูกส่งผ่านเป็นข้อโต้แย้งไปยังฟังก์ชั่นที่ฉันกำลังทดสอบ ฉันต้องการมีเวกเตอร์ของโครงสร้างเหล่านี้และกำลังมองหาวิธีการหนึ่งซับเพื่อเริ่มต้นโครงสร้างแต่ละอัน

ฉันลงเอยด้วยฟังก์ชัน constructor ใน struct ซึ่งฉันเชื่อว่ายังแนะนำในคำตอบสำหรับคำถามของคุณ

มันอาจเป็นวิธีปฏิบัติที่ไม่ดีที่จะให้อาร์กิวเมนต์แก่ตัวสร้างมีชื่อเหมือนกับตัวแปรสมาชิกสาธารณะซึ่งต้องใช้พthisอยน์เตอร์ ใครบางคนสามารถแนะนำการแก้ไขหากมีวิธีที่ดีกว่า

typedef struct testdatum_s {
    public:
    std::string argument1;
    std::string argument2;
    std::string argument3;
    std::string argument4;
    int count;

    testdatum_s (
        std::string argument1,
        std::string argument2,
        std::string argument3,
        std::string argument4,
        int count)
    {
        this->rotation = argument1;
        this->tstamp = argument2;
        this->auth = argument3;
        this->answer = argument4;
        this->count = count;
    }

} testdatum;

ซึ่งฉันใช้ในฟังก์ชั่นทดสอบของฉันเพื่อเรียกใช้ฟังก์ชันที่กำลังทดสอบด้วยอาร์กิวเมนต์ต่าง ๆ ดังนี้:

std::vector<testdatum> testdata;

testdata.push_back(testdatum("val11", "val12", "val13", "val14", 5));
testdata.push_back(testdatum("val21", "val22", "val23", "val24", 1));
testdata.push_back(testdatum("val31", "val32", "val33", "val34", 7));

for (std::vector<testdatum>::iterator i = testdata.begin(); i != testdata.end(); ++i) {
    function_in_test(i->argument1, i->argument2, i->argument3, i->argument4m i->count);
}

1

เป็นไปได้ แต่ถ้าโครงสร้างที่คุณกำลังเริ่มต้นเป็นโครงสร้าง POD (ข้อมูลเก่าธรรมดา) มันไม่สามารถมีวิธีการใด ๆ คอนสตรัคหรือแม้กระทั่งค่าเริ่มต้น


1

ใน C ++ ตัวเริ่มต้นของ C-style ถูกแทนที่ด้วยตัวสร้างซึ่งตามเวลาการคอมไพล์สามารถมั่นใจได้ว่ามีการดำเนินการเริ่มต้นที่ถูกต้องเท่านั้น (เช่นหลังจากการเริ่มต้นสมาชิกวัตถุจะสอดคล้องกัน)

เป็นวิธีปฏิบัติที่ดี แต่บางครั้งการเตรียมข้อมูลเบื้องต้นมีประโยชน์เช่นในตัวอย่างของคุณ OOP แก้นี้โดยคลาสนามธรรมหรือรูปแบบการออกแบบ Creational

ในความคิดของฉันการใช้วิธีที่ปลอดภัยนี้ฆ่าความเรียบง่ายและบางครั้งการแลกเปลี่ยนความปลอดภัยอาจมีราคาแพงเกินไปเนื่องจากรหัสง่าย ๆ ไม่จำเป็นต้องมีการออกแบบที่ซับซ้อน

ในฐานะทางเลือกอื่นฉันขอแนะนำให้กำหนดมาโครโดยใช้ lambdas เพื่อทำให้การเริ่มต้นง่ายขึ้นเพื่อให้ดูเหมือนกับสไตล์ C:

struct address {
  int street_no;
  const char *street_name;
  const char *city;
  const char *prov;
  const char *postal_code;
};
#define ADDRESS_OPEN [] { address _={};
#define ADDRESS_CLOSE ; return _; }()
#define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE

แมโคร ADDRESS ขยายเป็น

[] { address _={}; /* definition... */ ; return _; }()

ซึ่งสร้างและเรียกแลมบ์ดา พารามิเตอร์มาโครจะถูกคั่นด้วยเครื่องหมายจุลภาคดังนั้นคุณต้องใส่ initializer ไว้ในวงเล็บและเรียกเช่น

address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));

คุณสามารถเขียนแมโครเริ่มต้นทั่วไป

#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE

แต่สายก็สวยน้อยกว่าเล็กน้อย

address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));

อย่างไรก็ตามคุณสามารถกำหนดแมโคร ADDRESS โดยใช้แมโคร INIT ทั่วไปได้อย่างง่ายดาย

#define ADDRESS(x) INIT(address,x)

1

ใน GNUC ++ (ดูเหมือนว่าจะล้าสมัยตั้งแต่ 2.5 นานมาแล้ว :) ดูคำตอบได้ที่นี่: การเริ่มต้น C struct โดยใช้ป้ายกำกับ มันใช้งานได้ แต่อย่างไร ) มันเป็นไปได้ที่จะเริ่มต้นโครงสร้างเช่นนี้:

struct inventory_item {
    int bananas;
    int apples;
    int pineapples;
};

inventory_item first_item = {
    bananas: 2,
    apples: 49,
    pineapples: 4
};

0

แรงบันดาลใจจากคำตอบที่ประณีตมากนี้: ( https://stackoverflow.com/a/49572324/4808079 )

คุณสามารถทำการปิด lamba:

// Nobody wants to remember the order of these things
struct SomeBigStruct {
  int min = 1;
  int mean = 3 ;
  int mode = 5;
  int max = 10;
  string name;
  string nickname;
  ... // the list goes on
}

.

class SomeClass {
  static const inline SomeBigStruct voiceAmps = []{
    ModulationTarget $ {};
    $.min = 0;  
    $.nickname = "Bobby";
    $.bloodtype = "O-";
    return $;
  }();
}

หรือถ้าคุณต้องการที่จะแฟนซีมาก

#define DesignatedInit(T, ...)\
  []{ T ${}; __VA_ARGS__; return $; }()

class SomeClass {
  static const inline SomeBigStruct voiceAmps = DesignatedInit(
    ModulationTarget,
    $.min = 0,
    $.nickname = "Bobby",
    $.bloodtype = "O-",
  );
}

มีข้อบกพร่องบางอย่างที่เกี่ยวข้องกับเรื่องนี้ส่วนใหญ่เกี่ยวข้องกับสมาชิกที่ไม่ได้กำหนดค่าเริ่มต้น จากสิ่งที่คำตอบที่เชื่อมโยงแสดงความคิดเห็นมันรวบรวมได้อย่างมีประสิทธิภาพแม้ว่าฉันจะไม่ได้ทดสอบ

โดยรวมแล้วฉันแค่คิดว่ามันเป็นวิธีที่เรียบร้อย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.