ฉันจะหาประเภทของตัวแปรได้อย่างไร


130

ในภาษา C ++ เราจะหาชนิดของตัวแปรได้อย่างไร?


5
อาจซ้ำกันได้ของstackoverflow.com/questions/81870/print-variable-type-in-c
theharshest

7
cout << typeid (ตัวแปร) .name () << endl;
SRN

2
ใช้การค้นหาหรือ google :) stackoverflow.com/questions/81870/print-variable-type-in-c Theharshest is fast: D
Kariboo

14
@ คาริบูฉันใช้ Google และส่งฉันมาที่นี่
Michael Warner

คำถามนี้ยังไม่ชัดเจนเท่าที่เป็นอยู่และแม้จะเห็นคำตอบต่างๆแล้วก็ตาม มันไม่ชัดเจนว่าคำถามกำลังมองหาคำตอบที่ยอมรับได้
Antti Haapala

คำตอบ:


158

คุณสามารถใช้ตัวดำเนินการ typeid :

#include <typeinfo>
...
cout << typeid(variable).name() << endl;

15
@David - ดังนั้นiหมายถึงจำนวนเต็มในคอมไพเลอร์ของคุณ ชื่อที่ส่งคืนไม่ได้ระบุโดยมาตรฐาน
Bo Persson

11
เมื่อฉันใช้กับเวกเตอร์ <int> มันจะส่งคืน St6vectorIiSaIiEE WTF?
Boyan Kushlev

2
@BobbyBrown คุณไม่ได้อยู่คนเดียว !! google.co.uk/webhp#safe=off&q=St6vectorIiSaIiEE
Rich O'Kelly

5
ชื่อที่ส่งคืนtypeidเป็นแบบย่อมากเฉพาะคอมไพเลอร์และไม่ได้มีไว้สำหรับการบริโภคของมนุษย์ คุณสามารถ "demangle" ได้ (นั่นคือคำที่ใช้จริง!) ไม่ว่าจะเป็นรหัสที่มีบางอย่างเช่นgcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.htmlด้วยยูทิลิตี้บรรทัดคำสั่งเช่นc++filtหรือด้วยตัวถอดรหัสออนไลน์ต่างๆ เช่นdemangler.com
cincodenada

33

สำหรับการยืนยันแบบคงที่ C ++ 11 แนะนำdecltypeซึ่งมีประโยชน์มากในบางสถานการณ์



9

ความแตกต่างที่สำคัญระหว่าง C ++ และ Javascript คือ C ++ เป็นภาษาที่พิมพ์แบบคงที่ส่วนจาวาสคริปต์แบบ wile เป็นแบบไดนามิก

ในภาษาพิมพ์แบบไดนามิกตัวแปรสามารถมีสิ่งใดก็ได้และประเภทของมันจะถูกกำหนดโดยค่าที่เก็บไว้ในแต่ละช่วงเวลา ในภาษาที่พิมพ์แบบคงที่ประเภทของตัวแปรจะถูกประกาศและไม่สามารถเปลี่ยนแปลงได้

อาจมีการจัดส่งแบบไดนามิกและองค์ประกอบของออบเจ็กต์และการพิมพ์ย่อย (การสืบทอดและฟังก์ชันเสมือน) ตลอดจนการจัดส่งแบบคงที่และการพิมพ์แบบพิเศษ (ผ่านเทมเพลต CRTP) แต่ในกรณีใด ๆ คอมไพเลอร์จะต้องรู้จักประเภทของตัวแปร

หากคุณอยู่ในฐานะที่ไม่รู้ว่ามันคืออะไรหรืออาจเป็นเพราะคุณออกแบบบางอย่างเนื่องจากภาษามีระบบประเภทไดนามิก

หากเป็นเช่นนั้นคุณควรคิดใหม่เกี่ยวกับการออกแบบของคุณเนื่องจากมันกำลังเข้าสู่ดินแดนที่ไม่เป็นธรรมชาติสำหรับภาษาที่คุณใช้ (ส่วนใหญ่ชอบไปในมอเตอร์เวย์ที่มีหนอนผีเสื้อหรือในน้ำด้วยรถยนต์)


หาก C ++ มีการเปลี่ยนแปลงแบบไดนามิกฉันคิดว่ามันจะดีมากและฟังก์ชัน typeof และ parseInt ก็จะมีประโยชน์เช่นกัน แต่ฉันไม่รู้ว่าทำไมผู้ผลิต C ++ ถึงทำมันยากเกินไปเช่น! ใครบอกว่าเขียน cout << "String"
Waqas Tahir

มุ่งมั่นดีที่สุด !!!! # รวม <sstream> สตริง str ("1912"); int strtointval; สตริงสตรีม (str) >> strtointval;
Waqas Tahir

@Waqas เอ่ออะไรนะ? คนที่บอกว่าดีที่สุดคือคนที่กำหนดภาษาและ IMO พวกเขาก็มีคำพูดสุดท้ายในทุกสิ่งที่เกี่ยวข้องเช่นแนวทางปฏิบัติในการเขียนโค้ดที่ดีเป็นต้น คุณช่วยเรียบเรียงความคิดเห็นนั้นใหม่ให้เหมาะสมกว่านี้ได้ไหม
คดีของ Fund Monica

ฉันไม่เห็นด้วยอย่างยิ่ง Java, C #, PHP, Perl, Python และอื่น ๆ ได้รับการออกแบบใน C และ C ++ และไม่ใช่หนอนผีเสื้อ (เมื่อคุณสร้างแอปพลิเคชันฐานข้อมูลเพื่อเปิดตารางตัวแปรจากฐานข้อมูล 'ไม่รู้จัก' คุณต้องควบคุมประเภทฟิลด์เป็นรูปแบบตัวแปรและรอง vera ด้วยวิธี
dymanic

@TomeeNS: ไม่. พวกเขาจะเขียนใน C และ C ++ ไม่ได้รับการออกแบบ พวกเขาออกแบบมาเพื่อทำงานของพวกเขาพวกเขามีประเภทไดนามิกแม้ว่า C และ C ++ จะไม่ทำ ไม่มีอะไรแปลกเลย
Emilio Garavaglia

8

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

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


ไม่จริงสมมติว่าคุณมีคลาส Object และ Subclass Book ตอนนี้ลองนึกภาพคุณมีกล่องที่สามารถเก็บวัตถุได้มากมาย แต่ด้วยเหตุผลบางประการคุณต้องการแสดงรายการหนังสือทั้งหมดภายในกล่องนั้น การตรวจสอบประเภทนั้นสะอาดกว่ามากจากนั้นต้องเพิ่มเมธอด "type" ให้กับ Object จากนั้นแทนที่บน Book เพื่อส่งคืนสิ่งที่ต้องการเช่น "book"
Paulo Cesar

เช่นเดียวกับกฎใด ๆ มีข้อยกเว้น (ดังนั้น 'โดยปกติ' ของฉัน!) และคอนเทนเนอร์มักจะเพิ่มความซับซ้อนให้กับทฤษฎีประเภท ฉันไม่เคยรู้สึกเกินเลยกับ container-of-polymorphic-objects …ในกรณีส่วนใหญ่แล้วประเภทของคอนเทนเนอร์แบบเทมเพลตจะเพียงพอและสะอาดกว่ามาก
Pontus Gagge

คุณไม่ใช้เทมเพลตหรือไม่?
Bryan Grace

6

ฉันเชื่อว่าฉันมีกรณีการใช้งานที่ถูกต้องสำหรับการใช้ 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
}

1
TypeId: ฉันไม่สามารถใช้ typeid () บน Arduino ได้ typeid () ยังเป็นการตรวจสอบรันไทม์ไม่ใช่เวลาคอมไพล์ดังนั้นจึงไม่สามารถใช้เพื่อสร้างโค้ดที่ปรับให้เหมาะสมได้
Dan Truong

1
ใช่ไม่นี่ไม่ได้ทำอย่างที่คุณคิด typeidไม่สามารถตรวจสอบเวลาคอมไพล์แบบคงที่ได้ - ตามความหมายดังนั้นสิ่งนี้จึงไม่เอื้อต่อการเพิ่มประสิทธิภาพใด ๆ For a template function, I need to special case the code based on the template variableใช่แล้วสิ่งที่คุณต้องการจริงๆคือความหลากหลายแบบคงที่ผ่านสำนวน CRTP นี่คือสิ่งที่บรรลุ
underscore_d

4

ฉันไม่แน่ใจว่าคำตอบของฉันจะช่วยได้หรือไม่

คำตอบสั้น ๆ คือคุณไม่ต้องการ / ต้องการทราบประเภทของตัวแปรที่จะใช้

หากคุณต้องการกำหนดประเภทให้กับตัวแปรคงที่คุณสามารถใช้ 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);
}

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



0

หากคุณต้องการเปรียบเทียบระหว่างคลาสและประเภทที่รู้จักตัวอย่างเช่น:

class Example{};
...
Example eg = Example();

คุณสามารถใช้บรรทัดเปรียบเทียบนี้:

bool isType = string( typeid(eg).name() ).find("Example") != string::npos;

ซึ่งตรวจสอบว่าtypeidชื่อมีประเภทสตริง (ชื่อ typeid มีข้อมูลอื่นที่ยุ่งเหยิงดังนั้นควรทำs1.find(s2)แทน==)


-2

คุณสามารถเลือก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;
}

สังเกตว่าตัวแรกและตัวที่สองทำงานอย่างไร


การจดจำประเภทด้วยอักขระตัวแรกเป็นความคิดที่แย่มาก
Dmitry Kuzminov

โปรดระบุ Dmitry ให้เจาะจงมากขึ้นได้ไหม ฉันไม่เข้าใจประเด็นของคุณที่นี่
Pikachu

สิ่งนี้สามารถย่อให้สั้นลงstd::cout << "I'm a variable of type " << typeid(n).name()ได้ (เปลี่ยนคำใหม่เพื่อป้องกัน a / an artifacts แต่สามารถแก้ไขได้ด้วยการตรวจสอบอื่น) ถึงอย่างนั้นถ้าคุณต้องการการเปรียบเทียบอย่างแท้จริงมันจะดีกว่ามากที่จะทำtypeid(n) == typeid(int)
Zoe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.