ในการเขียนโปรแกรม C++ “std::any” จาก Standard Template Library (STL) จะแนะนำการพิมพ์แบบไดนามิกเพื่อจัดการกับข้อมูลที่ต่างกัน ต่างจากคอนเทนเนอร์แบบเดิม “std::any” อนุญาตให้จัดเก็บค่าประเภทใดก็ได้ภายในคอนเทนเนอร์เดียว เพิ่มความยืดหยุ่นในสถานการณ์ที่ไม่ทราบประเภทข้อมูลหรือเปลี่ยนแปลง ณ รันไทม์ วิธีการไม่เชื่อเรื่องพระเจ้าประเภทนี้ส่งเสริมการเขียนโปรแกรมทั่วไปซึ่งช่วยให้นักพัฒนาสามารถสร้างโค้ดที่ปรับเปลี่ยนได้และแสดงออกได้มากขึ้นในขณะที่ยังคงรักษาความปลอดภัยของประเภทไว้ ในการสำรวจนี้ เราจะเจาะลึกคุณสมบัติของ “std::any” รูปแบบการใช้งาน และตัวอย่างเชิงปฏิบัติที่แสดงให้เห็นถึงบทบาทในการเขียนโค้ด C++ ที่มีประสิทธิภาพและยืดหยุ่น
ตัวอย่างที่ 1: การใช้งานพื้นฐานของ Std::Any
ขั้นแรก เรามาสำรวจตัวอย่างที่ตรงไปตรงมาเพื่อสาธิตการใช้งานพื้นฐานของ “std::any” พิจารณาสถานการณ์ที่คุณต้องการฟังก์ชันเพื่อยอมรับพารามิเตอร์ประเภทต่างๆ:
นี่คือข้อมูลโค้ด:
#รวม
#รวม <ใดๆ>
กระบวนการเป็นโมฆะใดๆ ( const std::ใด ๆ & ค่า ) {
ถ้า ( ค่าhas_value ( ) ) {
มาตรฐาน::cout << 'ประเภทของมูลค่าที่เก็บไว้:' << ค่า.ประเภท ( ) .ชื่อ ( ) << มาตรฐาน::endl;
ถ้า ( ค่า.ประเภท ( ) == พิมพ์รหัส ( ภายใน ) ) {
มาตรฐาน::cout << 'ค่า: ' << มาตรฐาน::any_cast < ภายใน > ( ค่า ) << มาตรฐาน::endl;
} อื่น ถ้า ( ค่า.ประเภท ( ) == พิมพ์รหัส ( สองเท่า ) ) {
มาตรฐาน::cout << 'ค่า: ' << มาตรฐาน::any_cast < สองเท่า > ( ค่า ) << มาตรฐาน::endl;
} อื่น ถ้า ( ค่า.ประเภท ( ) == พิมพ์รหัส ( มาตรฐาน::string ) ) {
มาตรฐาน::cout << 'ค่า: ' << มาตรฐาน::any_cast < มาตรฐาน::string > ( ค่า ) << มาตรฐาน::endl;
} อื่น {
มาตรฐาน::cout << “ประเภทที่ไม่รองรับ!” << มาตรฐาน::endl;
}
} อื่น {
มาตรฐาน::cout << 'ไม่มีค่าที่เก็บอยู่ใน std::any' << มาตรฐาน::endl;
}
}
int หลัก ( ) {
กระบวนการใดๆ ( 42 ) ;
กระบวนการใดๆ ( 3.14 ) ;
กระบวนการใดๆ ( มาตรฐาน::string ( 'สวัสดี std::any!' ) ) ;
กระบวนการใดๆ ( 4.5ฟ ) ; // ไม่รองรับ พิมพ์
กลับ 0 ;
}
ในตัวอย่างนี้ เรากำหนดฟังก์ชัน 'processAny' ที่ใช้การอ้างอิง 'std::any' เป็นพารามิเตอร์และตรวจสอบเนื้อหา ภายในฟังก์ชัน ก่อนอื่นเราจะตรวจสอบดูว่าตัวแปร “std::any” มีค่าที่เก็บไว้โดยใช้ has_value() หรือไม่ หากมีค่าอยู่ เราจะกำหนดประเภทของค่าที่เก็บไว้โดยใช้ type().name() และดำเนินการพิมพ์ค่าที่เกี่ยวข้องตามประเภทของค่านั้น จากนั้นฟังก์ชันหลักจะสาธิตยูทิลิตีของ “processAny” โดยการเรียกมันด้วยประเภทต่างๆ ได้แก่ จำนวนเต็ม (42) คู่ (3.14) และสตริง (“Hello, std::any!”) ฟังก์ชันนี้จะจัดการแต่ละประเภทอย่างเหมาะสมและพิมพ์ค่าตามลำดับ อย่างไรก็ตาม เมื่อพยายามประมวลผลตัวเลขทศนิยม (4.5f) ซึ่งไม่ได้รับการสนับสนุนในตัวอย่างนี้ โปรแกรมจะจัดการกับสถานการณ์ได้อย่างสวยงามโดยการระบุว่าประเภทนั้นไม่ได้รับการสนับสนุน
ผลลัพธ์ที่สร้างขึ้นคือ:
สิ่งนี้แสดงให้เห็นว่า “std::any” ช่วยให้สามารถจัดการข้อมูลประเภทต่างๆ แบบไดนามิกได้อย่างไร ทำให้เป็นเครื่องมืออเนกประสงค์สำหรับการเขียนโปรแกรมทั่วไปใน C++
ตัวอย่างที่ 2: การจัดเก็บประเภทที่ผู้ใช้กำหนด
ตัวอย่างที่สองสำรวจว่าประเภทไดนามิกนี้ภายใน Standard Template Library (STL) รองรับโครงสร้างข้อมูลที่กำหนดเองได้อย่างไร โดยมุ่งเน้นไปที่ประเภทที่ผู้ใช้กำหนด ซึ่งเป็นโครงสร้างจุด เราจะแสดงให้เห็นว่า “std::any” จัดการกับอินสแตนซ์ของโครงสร้างดังกล่าวอย่างไร
นี่คือรหัส:
#รวม#รวม <ใดๆ>
คลาส MyClass {
สาธารณะ:
ห้องเรียนของฉัน ( ค่า int ) : ข้อมูล ( ค่า ) { }
เป็นโมฆะ printData ( ) ค่าคงที่ {
มาตรฐาน::cout << 'ข้อมูลใน MyClass:' << ข้อมูล << มาตรฐาน::endl;
}
ส่วนตัว:
ข้อมูลภายใน;
} ;
int หลัก ( ) {
std::anyanyObject = MyClass ( 42 ) ;
ถ้า ( anyObject.has_value ( ) ) {
อัตโนมัติ & myClassInstance = std::any_cast < ห้องเรียนของฉัน &> ( วัตถุใดๆ ) ;
myClassInstance.printData ( ) ;
} อื่น {
มาตรฐาน::cout << 'ไม่มีค่าที่เก็บอยู่ใน std::any' << มาตรฐาน::endl;
}
กลับ 0 ;
}
ในตัวอย่างโค้ด C++ นี้ เราสร้างตัวอย่างง่ายๆ เพื่อแสดงโดยใช้ประเภท “std::any” พร้อมด้วยคลาสที่ผู้ใช้กำหนดที่เรียกว่า “MyClass” ภายในคลาสจะมีตัวแปรสมาชิกส่วนตัวที่เรียกว่า “data” และวิธีการสาธารณะที่เรียกว่า printData() เพื่อแสดงค่าของข้อมูลนี้ ค่าจำนวนเต็มจะถูกส่งผ่านและกำหนดให้กับสมาชิก 'ข้อมูล' ในตัวสร้าง
ในฟังก์ชัน 'main' เราจะสร้างอินสแตนซ์อ็อบเจ็กต์ 'MyClass' ด้วยค่าเริ่มต้น 42 จากนั้นจัดเก็บไว้ในตัวแปร 'std::any' ชื่อ 'anyObject' สิ่งนี้แสดงให้เห็นถึงความสามารถของ “std::any” เพื่อเก็บอินสแตนซ์ของคลาสที่ผู้ใช้กำหนด
ต่อไปนี้ เราใช้คำสั่ง 'if' เพื่อตรวจสอบว่า 'anyObject' มีค่าหรือไม่โดยใช้เมธอด has_value() หากมีค่า เราจะดึงวัตถุที่เก็บไว้โดยใช้ “std::any_cast” “std::any_cast” ใช้กับอาร์กิวเมนต์เทมเพลต “MyClass&” เพื่อส่งวัตถุที่เก็บไว้ไปยังการอ้างอิงของ “MyClass” จากนั้นการอ้างอิงนี้ 'myClassInstance' จะใช้เพื่อเรียกใช้เมธอด printData() ซึ่งแสดงความสามารถในการเข้าถึงและดำเนินการกับประเภทที่ผู้ใช้กำหนดซึ่งเก็บไว้ภายใน 'std::any'
หากไม่มีค่าถูกเก็บไว้ใน “std::any” เราจะพิมพ์ข้อความที่แสดงถึงสิ่งนี้ การตรวจสอบตามเงื่อนไขนี้ช่วยให้แน่ใจว่าเราจัดการกับสถานการณ์ที่ตัวแปร “std::any” อาจว่างเปล่า
นี่คือผลลัพธ์:
ตัวอย่างที่ 3: คอนเทนเนอร์ประเภทผสม
ในการเขียนโปรแกรม “คอนเทนเนอร์แบบผสม” หมายถึงโครงสร้างข้อมูลที่สามารถเก็บองค์ประกอบของประเภทข้อมูลที่หลากหลายและอาจไม่เกี่ยวข้องกัน ความยืดหยุ่นนี้มีประโยชน์เมื่อต้องรับมือกับสถานการณ์ที่ไม่ทราบประเภทข้อมูลในขณะคอมไพล์หรือมีการเปลี่ยนแปลงแบบไดนามิกระหว่างการทำงานของโปรแกรม ในภาษา C++ “std::any” เป็นตัวอย่างแนวคิดนี้ โดยอนุญาตให้สร้างคอนเทนเนอร์เดียวเพื่อเก็บค่าประเภทต่างๆ
มาสำรวจสถานการณ์ที่เราสร้างคอนเทนเนอร์ที่มีประเภทต่างๆ กัน:
#รวม#รวม <ใดๆ>
#รวม <เวกเตอร์>
int หลัก ( ) {
มาตรฐาน::เวกเตอร์ < มาตรฐาน::ใดก็ได้ > คอนเทนเนอร์ผสม;
mixContainer.push_back ( 42 ) ;
mixContainer.push_back ( 3.14 ) ;
mixContainer.push_back ( มาตรฐาน::string ( 'สวัสดี' ) ) ;
mixContainer.push_back ( จริง ) ;
สำหรับ ( เชื่อมต่ออัตโนมัติ & องค์ประกอบ : mixContainer ) {
ถ้า ( องค์ประกอบ.ประเภท ( ) == พิมพ์รหัส ( ภายใน ) ) {
มาตรฐาน::cout << 'จำนวนเต็ม:' << มาตรฐาน::any_cast < ภายใน > ( องค์ประกอบ ) << มาตรฐาน::endl;
} อื่น ถ้า ( องค์ประกอบ.ประเภท ( ) == พิมพ์รหัส ( สองเท่า ) ) {
มาตรฐาน::cout << 'สองเท่า: ' << มาตรฐาน::any_cast < สองเท่า > ( องค์ประกอบ ) << มาตรฐาน::endl;
} อื่น ถ้า ( องค์ประกอบ.ประเภท ( ) == พิมพ์รหัส ( มาตรฐาน::string ) ) {
มาตรฐาน::cout << 'สตริง:' << มาตรฐาน::any_cast < มาตรฐาน::string > ( องค์ประกอบ ) << มาตรฐาน::endl;
} อื่น ถ้า ( องค์ประกอบ.ประเภท ( ) == พิมพ์รหัส ( บูล ) ) {
มาตรฐาน::cout << 'บูลีน:' << มาตรฐาน::any_cast < บูล > ( องค์ประกอบ ) << มาตรฐาน::endl;
} อื่น {
มาตรฐาน::cout << 'ไม่ทราบประเภท' << มาตรฐาน::endl;
}
}
กลับ 0 ;
}
ในภาพประกอบนี้ เราสาธิตแนวคิดของคอนเทนเนอร์แบบผสมโดยใช้ C++ และฟีเจอร์ “std::any” เราสร้าง “std::vector
เมื่อเราวนซ้ำผ่าน “mixedContainer” โดยใช้ลูป “for” เราจะใช้ฟังก์ชัน type() เพื่อระบุประเภทข้อมูลของแต่ละองค์ประกอบแบบไดนามิก ด้วยการใช้ “std::any_cast” เราแยกและพิมพ์ค่าที่เกี่ยวข้องตามประเภทของค่าเหล่านั้น ตัวอย่างเช่น หากองค์ประกอบเป็นประเภท 'int' เราจะพิมพ์เป็นจำนวนเต็ม หากเป็นประเภท 'double' เราจะพิมพ์เป็น double และอื่นๆ
นี่คือผลลัพธ์ที่สร้างขึ้น:
ตัวอย่างที่ 4: การจัดการข้อผิดพลาดกับ Std::Any
การจัดการข้อผิดพลาดเมื่อใช้ “std::any” เกี่ยวข้องกับการตรวจสอบว่ารองรับประเภทนั้นหรือไม่หรือเก็บค่าไว้หรือไม่ ในตัวอย่างนี้ เราสาธิตวิธีจัดการกับประเภทที่ไม่รองรับ:
#รวม#รวม <ใดๆ>
int หลัก ( ) {
มาตรฐาน::ใดๆ myAny = 42 ;
พยายาม {
ค่าสองเท่า = std::any_cast < สองเท่า > ( ของฉันอันไหนก็ได้ ) ;
มาตรฐาน::cout << 'ค่า: ' << ค่า << มาตรฐาน::endl;
} จับ ( const มาตรฐาน::bad_any_cast & มันคือ ) {
มาตรฐาน::cerr << 'ข้อผิดพลาด: ' << จ.อะไร ( ) << มาตรฐาน::endl;
}
กลับ 0 ;
}
เราเริ่มต้นด้วยการเริ่มต้นตัวแปร “std::any” “myAny” ด้วยค่า 42 ของประเภทจำนวนเต็ม ภายในบล็อก “ลอง” ที่ตามมา เราจะพยายามแปลงค่าจำนวนเต็มนี้เป็น “สองเท่า” โดยใช้การดำเนินการ “std::any_cast
เพื่อจัดการข้อผิดพลาดที่อาจเกิดขึ้นนี้อย่างสวยงาม เราใช้การจัดการข้อยกเว้นด้วยบล็อก 'catch' ที่ออกแบบมาเพื่อตรวจจับประเภทข้อยกเว้นเฉพาะของ 'std::bad_any_cast' ในกรณีที่ส่งไม่สำเร็จ บล็อก 'catch' จะถูกเปิดใช้งานและเราสร้างข้อความแสดงข้อผิดพลาดโดยใช้ 'std::cerr' เพื่อสื่อสารลักษณะของข้อผิดพลาด กลยุทธ์การจัดการข้อผิดพลาดนี้ช่วยให้มั่นใจได้ว่าโปรแกรมของเราสามารถจัดการกับสถานการณ์ที่ประเภทที่พยายามสร้างขัดแย้งกับประเภทจริงที่จัดเก็บไว้ในตัวแปร “std::any” ได้อย่างสวยงาม
บทสรุป
ในบทความนี้ เราได้สำรวจการใช้งานของ “std::any” ใน C++ ซึ่งเป็นคอนเทนเนอร์ประเภทไดนามิกที่นำมาใช้ใน C++ สำหรับค่าประเภทต่างๆ เราแสดงให้เห็นถึงความเก่งกาจของมันผ่านตัวอย่างต่างๆ โดยจัดแสดงสถานการณ์ต่างๆ ตั้งแต่การใช้งานขั้นพื้นฐานไปจนถึงการจัดการประเภทที่ผู้ใช้กำหนดและคอลเลกชันที่แตกต่างกัน เราได้สาธิตการใช้งานจริงในสถานการณ์ที่ไม่ทราบประเภทของข้อมูลในขณะรวบรวม นอกจากนี้ เรายังสำรวจเกี่ยวกับเทคนิคการจัดการข้อผิดพลาด โดยเน้นถึงความสำคัญของการจัดการประเภทที่ไม่ได้รับการสนับสนุนอย่างสวยงามผ่านการจัดการข้อยกเว้น