ในภาษา C ++ เราจะหาชนิดของตัวแปรได้อย่างไร?
ในภาษา C ++ เราจะหาชนิดของตัวแปรได้อย่างไร?
คำตอบ:
คุณสามารถใช้ตัวดำเนินการ typeid :
#include <typeinfo>
...
cout << typeid(variable).name() << endl;
i
หมายถึงจำนวนเต็มในคอมไพเลอร์ของคุณ ชื่อที่ส่งคืนไม่ได้ระบุโดยมาตรฐาน
typeid
เป็นแบบย่อมากเฉพาะคอมไพเลอร์และไม่ได้มีไว้สำหรับการบริโภคของมนุษย์ คุณสามารถ "demangle" ได้ (นั่นคือคำที่ใช้จริง!) ไม่ว่าจะเป็นรหัสที่มีบางอย่างเช่นgcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.htmlด้วยยูทิลิตี้บรรทัดคำสั่งเช่นc++filt
หรือด้วยตัวถอดรหัสออนไลน์ต่างๆ เช่นdemangler.com
สำหรับการยืนยันแบบคงที่ C ++ 11 แนะนำdecltype
ซึ่งมีประโยชน์มากในบางสถานการณ์
หากคุณมีตัวแปร
int k;
คุณสามารถรับประเภทได้โดยใช้
cout << typeid(k).name() << endl;
ดูหัวข้อต่อไปนี้ใน SO: คำถามที่คล้ายกัน
ความแตกต่างที่สำคัญระหว่าง C ++ และ Javascript คือ C ++ เป็นภาษาที่พิมพ์แบบคงที่ส่วนจาวาสคริปต์แบบ wile เป็นแบบไดนามิก
ในภาษาพิมพ์แบบไดนามิกตัวแปรสามารถมีสิ่งใดก็ได้และประเภทของมันจะถูกกำหนดโดยค่าที่เก็บไว้ในแต่ละช่วงเวลา ในภาษาที่พิมพ์แบบคงที่ประเภทของตัวแปรจะถูกประกาศและไม่สามารถเปลี่ยนแปลงได้
อาจมีการจัดส่งแบบไดนามิกและองค์ประกอบของออบเจ็กต์และการพิมพ์ย่อย (การสืบทอดและฟังก์ชันเสมือน) ตลอดจนการจัดส่งแบบคงที่และการพิมพ์แบบพิเศษ (ผ่านเทมเพลต CRTP) แต่ในกรณีใด ๆ คอมไพเลอร์จะต้องรู้จักประเภทของตัวแปร
หากคุณอยู่ในฐานะที่ไม่รู้ว่ามันคืออะไรหรืออาจเป็นเพราะคุณออกแบบบางอย่างเนื่องจากภาษามีระบบประเภทไดนามิก
หากเป็นเช่นนั้นคุณควรคิดใหม่เกี่ยวกับการออกแบบของคุณเนื่องจากมันกำลังเข้าสู่ดินแดนที่ไม่เป็นธรรมชาติสำหรับภาษาที่คุณใช้ (ส่วนใหญ่ชอบไปในมอเตอร์เวย์ที่มีหนอนผีเสื้อหรือในน้ำด้วยรถยนต์)
โดยปกติแล้วการต้องการค้นหาประเภทของตัวแปรใน C ++ เป็นคำถามที่ไม่ถูกต้อง มีแนวโน้มที่จะเป็นสิ่งที่คุณดำเนินการจากภาษาขั้นตอนเช่น C หรือ Pascal
หากคุณต้องการที่จะมีพฤติกรรมที่แตกต่างกันรหัสขึ้นอยู่กับชนิดพยายามที่จะเรียนรู้เกี่ยวกับเช่นโอเวอร์โหลดฟังก์ชั่นและวัตถุมรดก สิ่งนี้จะไม่สมเหตุสมผลในวันแรกของ C ++ แต่ให้รักษาไว้
ฉันเชื่อว่าฉันมีกรณีการใช้งานที่ถูกต้องสำหรับการใช้ typeid () เช่นเดียวกับที่ใช้ sizeof () ได้ สำหรับฟังก์ชันเทมเพลตฉันจำเป็นต้องใช้โค้ดตามตัวแปรเทมเพลตเป็นกรณีพิเศษเพื่อให้ฉันมีฟังก์ชันและความยืดหยุ่นสูงสุด
มีขนาดกะทัดรัดและบำรุงรักษาได้มากกว่าการใช้ความหลากหลายในการสร้างหนึ่งอินสแตนซ์ของฟังก์ชันสำหรับแต่ละประเภทที่รองรับ แม้ว่าในกรณีนี้ฉันอาจใช้เคล็ดลับนี้เพื่อเขียนเนื้อหาของฟังก์ชันเพียงครั้งเดียว:
โปรดทราบว่าเนื่องจากโค้ดใช้เทมเพลตคำสั่งสวิตช์ด้านล่างควรแก้ไขแบบคงที่เป็นบล็อกโค้ดเดียวโดยเพิ่มประสิทธิภาพ AFAIK กรณีเท็จทั้งหมด
ลองพิจารณาตัวอย่างนี้ซึ่งเราอาจต้องจัดการกับ Conversion หาก T เป็นประเภทหนึ่งเทียบกับอีกประเภทหนึ่ง ฉันใช้สำหรับความเชี่ยวชาญระดับคลาสเพื่อเข้าถึงฮาร์ดแวร์โดยที่ฮาร์ดแวร์จะใช้ประเภท myClassA หรือ myClassB หากไม่ตรงกันฉันต้องใช้เวลาในการแปลงข้อมูล
switch ((typeid(T)) {
case typeid(myClassA):
// handle that case
break;
case typeid(myClassB):
// handle that case
break;
case typeid(uint32_t):
// handle that case
break;
default:
// handle that case
}
typeid
ไม่สามารถตรวจสอบเวลาคอมไพล์แบบคงที่ได้ - ตามความหมายดังนั้นสิ่งนี้จึงไม่เอื้อต่อการเพิ่มประสิทธิภาพใด ๆ For a template function, I need to special case the code based on the template variable
ใช่แล้วสิ่งที่คุณต้องการจริงๆคือความหลากหลายแบบคงที่ผ่านสำนวน CRTP นี่คือสิ่งที่บรรลุ
ฉันไม่แน่ใจว่าคำตอบของฉันจะช่วยได้หรือไม่
คำตอบสั้น ๆ คือคุณไม่ต้องการ / ต้องการทราบประเภทของตัวแปรที่จะใช้
หากคุณต้องการกำหนดประเภทให้กับตัวแปรคงที่คุณสามารถใช้ auto
ในกรณีที่ซับซ้อนกว่าที่คุณต้องการใช้ "อัตโนมัติ" ในคลาสหรือโครงสร้างฉันขอแนะนำให้ใช้เทมเพลตที่มีประเภทปฏิเสธ
ตัวอย่างเช่นสมมติว่าคุณกำลังใช้ไลบรารีของคนอื่นและมีตัวแปรชื่อ "Unknown_var" และคุณต้องการใส่ในเวกเตอร์หรือโครงสร้างคุณสามารถทำได้ทั้งหมด:
template <typename T>
struct my_struct {
int some_field;
T my_data;
};
vector<decltype(unknown_var)> complex_vector;
vector<my_struct<decltype(unknown_var)> > simple_vector
หวังว่านี่จะช่วยได้
แก้ไข: เพื่อการวัดที่ดีนี่เป็นกรณีที่ซับซ้อนที่สุดที่ฉันคิดได้นั่นคือการมีตัวแปรที่ไม่รู้จักทั่วโลก ในกรณีนี้คุณจะต้องใช้ตัวแปร c ++ 14 และเทมเพลต
สิ่งนี้:
template<typename T> vector<T> global_var;
void random_func (auto unknown_var) {
global_var<decltype(unknown_var)>.push_back(unknown_var);
}
มันยังค่อนข้างน่าเบื่อ แต่มันก็ใกล้เคียงกับที่คุณสามารถเข้าถึงภาษาที่ไม่ใช้ตัวพิมพ์ได้ ตรวจสอบให้แน่ใจว่าเมื่อใดก็ตามที่คุณอ้างอิงตัวแปรเทมเพลตให้ใส่ข้อมูลจำเพาะของเทมเพลตไว้ที่นั่นเสมอ
#include <typeinfo>
...
string s = typeid(YourClass).name()
หากคุณต้องการเปรียบเทียบระหว่างคลาสและประเภทที่รู้จักตัวอย่างเช่น:
class Example{};
...
Example eg = Example();
คุณสามารถใช้บรรทัดเปรียบเทียบนี้:
bool isType = string( typeid(eg).name() ).find("Example") != string::npos;
ซึ่งตรวจสอบว่าtypeid
ชื่อมีประเภทสตริง (ชื่อ typeid มีข้อมูลอื่นที่ยุ่งเหยิงดังนั้นควรทำs1.find(s2)
แทน==
)
คุณสามารถเลือกtypeid(x).name()
ที่ x เป็นชื่อตัวแปรได้ มันส่งคืนตัวชี้ const char ไปยังชนิดข้อมูล ตอนนี้ดูรหัสต่อไปนี้
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n = 36;
char c = 'A';
double d = 1.2;
if(*(typeid(n).name()) == 'i'){
cout << "I am an Integer variable" << endl;
}
if(*((char *) typeid(d).name()) == 'd'){
cout << "I am a Double variable" << endl;
}
if(*((char *) typeid(c).name()) == 'c'){
cout << "I am a Char variable" << endl;
}
return 0;
}
สังเกตว่าตัวแรกและตัวที่สองทำงานอย่างไร
std::cout << "I'm a variable of type " << typeid(n).name()
ได้ (เปลี่ยนคำใหม่เพื่อป้องกัน a / an artifacts แต่สามารถแก้ไขได้ด้วยการตรวจสอบอื่น) ถึงอย่างนั้นถ้าคุณต้องการการเปรียบเทียบอย่างแท้จริงมันจะดีกว่ามากที่จะทำtypeid(n) == typeid(int)