สมมติว่าฉันมีฟังก์ชันเทมเพลตและสองคลาส
class animal {
}
class person {
}
template<class T>
void foo() {
if (T is animal) {
kill();
}
}
ฉันจะตรวจสอบ T คือสัตว์ได้อย่างไร? ฉันไม่ต้องการให้มีบางอย่างที่ตรวจสอบระหว่างเวลาทำงาน ขอบคุณ
สมมติว่าฉันมีฟังก์ชันเทมเพลตและสองคลาส
class animal {
}
class person {
}
template<class T>
void foo() {
if (T is animal) {
kill();
}
}
ฉันจะตรวจสอบ T คือสัตว์ได้อย่างไร? ฉันไม่ต้องการให้มีบางอย่างที่ตรวจสอบระหว่างเวลาทำงาน ขอบคุณ
คำตอบ:
ใช้is_same:
#include <type_traits>
template <typename T>
void foo()
{
if (std::is_same<T, animal>::value) { /* ... */ } // optimizable...
}
โดยปกติแล้วนั่นเป็นการออกแบบที่ไม่สามารถใช้งานได้โดยสิ้นเชิงและคุณต้องการที่จะเชี่ยวชาญ :
template <typename T> void foo() { /* generic implementation */ }
template <> void foo<animal>() { /* specific for T = animal */ }
โปรดทราบว่าเป็นเรื่องผิดปกติที่จะมีเทมเพลตฟังก์ชันที่มีอาร์กิวเมนต์ที่ชัดเจน (ไม่อนุมาน) ไม่ใช่เรื่องแปลก แต่มักจะมีแนวทางที่ดีกว่า
Tไม่ได้อนุมานคุณจึงทำอะไรได้ไม่มาก คุณสามารถออกจากแม่แบบหลัก unimplemented is_sameและสร้างความเชี่ยวชาญหรือคุณอาจจะเพิ่มการยืนยันคงที่พร้อม
ฉันคิดว่าวันนี้มันจะดีกว่าที่จะใช้ แต่เฉพาะกับ C ++ 17
#include <type_traits>
template <typename T>
void foo() {
if constexpr (std::is_same_v<T, animal>) {
// use type specific operations...
}
}
หากคุณใช้การดำเนินการเฉพาะบางประเภทใน if expression body โดยไม่มีconstexprโค้ดนี้จะไม่คอมไพล์
std::is_same<T, U>::valueใช้สั้นกว่า:std::is_same_v<T, U>
ใน C ++ 17 เราสามารถใช้ตัวแปรสายพันธุ์
ในการใช้งานstd::variantคุณต้องรวมส่วนหัว:
#include <variant>
หลังจากนั้นคุณสามารถเพิ่มstd::variantโค้ดของคุณได้ดังนี้:
using Type = std::variant<Animal, Person>;
template <class T>
void foo(Type type) {
if (std::is_same_v<type, Animal>) {
// Do stuff...
} else {
// Do stuff...
}
}
typeซึ่งเป็นค่าประเภทTypeหรือแม่แบบซึ่งไม่ได้ทำให้ความรู้สึกที่นี่) ไม่ได้มีความหมายในบริบทของis_same_v variantที่สอดคล้องกัน "ลักษณะ" holds_alternativeเป็น
std::variantไม่จำเป็นโดยสิ้นเชิงที่นี่
คุณสามารถเชี่ยวชาญเทมเพลตของคุณโดยพิจารณาจากสิ่งที่ส่งไปยังพารามิเตอร์เช่นนี้:
template <> void foo<animal> {
}
Tโปรดทราบว่านี้จะสร้างฟังก์ชั่นใหม่ทั้งหมดขึ้นอยู่กับชนิดที่ผ่านการเป็น โดยปกติแล้วจะดีกว่าเนื่องจากช่วยลดความยุ่งเหยิงและเป็นเหตุผลหลักที่เรามีเทมเพลตตั้งแต่แรก