Làm cách nào để lấy kiểu của một biến?


130

Trong C ++, làm cách nào để tìm kiểu của một biến?



7
cout << typeid (biến) .name () << endl;
SRN

2
Sử dụng tìm kiếm hoặc google :) stackoverflow.com/questions/81870/print-variable-type-in-c Theharshest là nhanh: D
Kariboo

14
@Kariboo, tôi đã sử dụng Google và nó đã gửi tôi đến đây.
Michael Warner

Câu hỏi này rất không rõ ràng, và ngay cả sau khi xem các câu trả lời khác nhau; không có nghĩa là rõ ràng rằng câu hỏi đang tìm kiếm câu trả lời được chấp nhận.
Antti Haapala

Câu trả lời:


158

Bạn có thể sử dụng toán tử typeid :

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

15
@David - Vì vậy, icó nghĩa là số nguyên trên trình biên dịch của bạn. Các tên được trả về không được chỉ định bởi tiêu chuẩn.
Bo Persson

11
Khi tôi sử dụng nó trên vector <int>, nó trả về St6vectorIiSaIiEE. WTF?
Boyan Kushlev

2
@BobbyBrown bạn không đơn độc !! google.co.uk/webhp#safe=off&q=St6vectorIiSaIiEE
Rich O'Kelly,

5
Các tên được trả về typeidrất viết tắt, dành riêng cho trình biên dịch và không dành cho con người. Bạn có thể "gỡ rối" chúng (đó là thuật ngữ thực tế!), Bằng mã với một cái gì đó như gcc.gnu.org/onlineocs/libstdc++/manual/ext_demangling.html , với các tiện ích dòng lệnh như c++filthoặc với bất kỳ trình gỡ rối trực tuyến nào khác nhau chẳng hạn như demangler.com .
cincodenada

33

Đối với các xác nhận tĩnh, C ++ 11 được giới thiệu decltypekhá hữu ích trong một số trường hợp nhất định.


12

Nếu bạn có một biến

int k;

Bạn có thể lấy loại của nó bằng cách sử dụng

cout << typeid(k).name() << endl;

Xem chủ đề sau trên SO: Câu hỏi tương tự


9

Sự khác biệt chính giữa C ++ và Javascript là C ++ là một ngôn ngữ kiểu tĩnh, javascript wile là động.

Trong các ngôn ngữ định kiểu động, một biến có thể chứa bất cứ thứ gì và kiểu của nó được cung cấp bởi giá trị mà nó nắm giữ, theo từng thời điểm. Trong các ngôn ngữ định kiểu tĩnh, kiểu của một biến được khai báo và không thể thay đổi.

Có thể có công văn động và thành phần đối tượng và kiểu con (chức năng kế thừa và ảo) cũng như kiểu điều khiển tĩnh và siêu kiểu (thông qua mẫu CRTP), nhưng trong mọi trường hợp, trình biên dịch phải biết kiểu của biến.

Nếu bạn không biết nó là gì hoặc có thể là gì, thì đó là vì bạn đã thiết kế thứ gì đó như ngôn ngữ có hệ thống kiểu động.

Nếu đúng như vậy, tốt hơn hết bạn nên nghĩ lại thiết kế của mình, vì nó đang đi vào một vùng đất không hợp với ngôn ngữ bạn đang sử dụng (hầu hết giống như đi trên đường cao tốc với một con sâu bướm hoặc trong nước với một chiếc ô tô)


Nếu C ++ có sự thay đổi động thì tôi nghĩ nó sẽ rất tuyệt và các hàm typeof và parseInt, parseFloat cũng sẽ hữu ích nhưng tôi không biết tại sao các nhà sản xuất C ++ lại làm cho nó quá khó, chẳng hạn! ai nói viết cout << "String"
Waqas Tahir thì tốt quá,

quyết tâm là tốt nhất !!!! #include <sstream> string str ("1912"); int strtointval; stringstream (str) >> strtointval;
Waqas Tahir

@Waqas Uh, sao? Những người nói rằng nó tốt nhất là những người xác định ngôn ngữ và IMO, họ có khá nhiều tiếng nói cuối cùng về bất cứ điều gì liên quan đến nó - ví dụ như các phương pháp mã hóa tốt. Bạn có thể diễn đạt lại nhận xét đó để nó có ý nghĩa hơn không?
Vụ kiện của Fund Monica

Tôi hoàn toàn không đồng ý. Java, C #, PHP, Perl, Python, v.v. được thiết kế bằng C và C ++ và chúng không phải là sâu bướm. (Khi bạn tạo một ứng dụng cơ sở dữ liệu cho các bảng biến mở cửa từ cơ sở dữ liệu 'vô danh' bạn cần phải loại lĩnh vực kiểm soát để chương trình biến và ngược vera trong một 'rất' cách dymanic;))
TomeeNS

@TomeeNS: Không. Chúng được viết bằng C và C ++, không được thiết kế . Chúng được thiết kế để thực hiện công việc của chúng, chúng có kiểu động ngay cả khi bản thân C và C ++ thì không. Điều đó không có gì lạ với nó.
Emilio Garavaglia

8

Thông thường, muốn tìm kiểu của một biến trong C ++ là một câu hỏi sai. Nó có xu hướng là thứ mà bạn mang theo từ các ngôn ngữ thủ tục như C hoặc Pascal chẳng hạn.

Nếu bạn muốn viết mã các hành vi khác nhau tùy thuộc vào loại, hãy cố gắng tìm hiểu về ví dụ: nạp chồng hàmkế thừa đối tượng . Điều này sẽ không có ý nghĩa ngay lập tức vào ngày đầu tiên sử dụng C ++ của bạn, nhưng hãy tiếp tục.


Không thực sự, giả sử bạn có một Đối tượng lớp và một Sách lớp con. Bây giờ hãy tưởng tượng bạn có một Hộp có thể lưu trữ rất nhiều Đối tượng, nhưng vì lý do nào đó mà bạn muốn liệt kê tất cả Sách bên trong nó. Kiểm tra các loại có nhiều bụi thì phải thêm một phương pháp "loại" để đối tượng và sau đó ghi đè lên nó trên sách để trả lại một cái gì đó như "cuốn sách"
Paulo Cesar

Như với bất kỳ quy tắc nào, có những ngoại lệ (do đó là 'thường' của tôi!), Và các vùng chứa có xu hướng tăng thêm độ phức tạp cho lý thuyết kiểu. Tôi chưa bao giờ quan tâm nhiều đến các container-các-đối tượng đa hình… trong hầu hết các trường hợp, các loại container đồng nhất được tạo khuôn mẫu là đủ và sạch hơn nhiều.
Pontus Gpris

Bạn không sử dụng mẫu?
Bryan Grace

6

Tôi tin rằng tôi có một trường hợp sử dụng hợp lệ cho việc sử dụng typeid (), giống như cách nó hợp lệ để sử dụng sizeof (). Đối với một hàm mẫu, tôi cần viết hoa đặc biệt cho mã dựa trên biến mẫu, để tôi cung cấp chức năng và tính linh hoạt tối đa.

Nó nhỏ gọn và dễ bảo trì hơn nhiều so với việc sử dụng tính đa hình, để tạo một phiên bản của hàm cho mỗi kiểu được hỗ trợ. Ngay cả trong trường hợp đó, tôi có thể sử dụng thủ thuật này để viết phần thân của hàm chỉ một lần:

Lưu ý rằng vì mã sử dụng các mẫu, câu lệnh switch bên dưới sẽ giải quyết tĩnh thành chỉ một khối mã, tối ưu hóa loại bỏ tất cả các trường hợp sai, AFAIK.

Hãy xem xét ví dụ này, nơi chúng ta có thể cần xử lý chuyển đổi nếu T là một loại so với một loại khác. Tôi sử dụng nó cho chuyên môn hóa lớp để truy cập phần cứng trong đó phần cứng sẽ sử dụng loại myClassA hoặc myClassB. Khi không khớp, tôi cần dành thời gian chuyển đổi dữ liệu.

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: Tôi không thể sử dụng typeid () trên Arduino. Ngoài ra typeid () là kiểm tra thời gian chạy , không phải thời gian biên dịch nên nó không thể được sử dụng để tạo mã tối ưu hóa.
Đan Trường

1
Vâng, không, điều này không làm những gì bạn nghĩ nó đã làm. typeidđơn giản không thể là một kiểm tra tĩnh, thời gian biên dịch - theo định nghĩa - vì vậy điều này không tạo điều kiện cho bất kỳ tối ưu hóa nào. For a template function, I need to special case the code based on the template variableĐúng vậy, điều bạn thực sự muốn là tính đa hình tĩnh thông qua thành ngữ CRTP. Đây chính xác là những gì đạt được.
underscore_d

4

Tôi không chắc liệu câu trả lời của tôi có hữu ích hay không.

Câu trả lời ngắn gọn là, bạn không thực sự cần / muốn biết loại biến để sử dụng nó.

Nếu bạn cần cung cấp một kiểu cho một biến tĩnh, thì bạn có thể chỉ cần sử dụng auto.

Trong trường hợp phức tạp hơn khi bạn muốn sử dụng "auto" trong một lớp hoặc cấu trúc, tôi khuyên bạn nên sử dụng mẫu với kiểu khai báo.

Ví dụ: giả sử bạn đang sử dụng thư viện của người khác và nó có một biến gọi là "known_var" và bạn muốn đặt nó trong một vectơ hoặc cấu trúc, bạn hoàn toàn có thể làm điều này:

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

Hi vọng điêu nay co ich.

CHỈNH SỬA: Để có biện pháp tốt, đây là trường hợp phức tạp nhất mà tôi có thể nghĩ đến: có một biến toàn cục không xác định. Trong trường hợp này, bạn sẽ cần c ++ 14 và biến mẫu.

Một cái gì đó như thế này:

template<typename T> vector<T> global_var;

void random_func (auto unknown_var) {
    global_var<decltype(unknown_var)>.push_back(unknown_var);
}

Nó vẫn còn một chút tẻ nhạt nhưng nó gần như bạn có thể tiếp cận với các ngôn ngữ không đánh máy. Chỉ cần đảm bảo rằng bất cứ khi nào bạn tham chiếu đến biến mẫu, hãy luôn đặt đặc tả mẫu ở đó.


2
#include <typeinfo>

...
string s = typeid(YourClass).name()

0

Nếu bạn cần so sánh giữa một lớp và một kiểu đã biết, ví dụ:

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

Bạn có thể sử dụng dòng so sánh này:

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

kiểm tra typeidtên chứa kiểu chuỗi (tên typeid có dữ liệu bị xáo trộn khác, vì vậy tốt nhất bạn nên làm s1.find(s2)thay vì ==).


-2

Bạn chắc chắn có thể sử dụng typeid(x).name()x là tên biến. Nó thực sự trả về một con trỏ const char cho kiểu dữ liệu. Bây giờ, hãy xem đoạn mã sau.

#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;
}

Lưu ý cách đầu tiên và thứ hai cả hai nếu hoạt động.


Nhận dạng kiểu bằng ký tự đầu tiên là một ý kiến ​​rất tồi.
Dmitry Kuzminov

Bạn có thể vui lòng nói rõ hơn Dmitry được không? Tôi không hiểu ý của bạn ở đây.
Pikachu

Điều này chỉ có thể được rút ngắn thành std::cout << "I'm a variable of type " << typeid(n).name(). (được đổi tên để ngăn chặn a / an tạo tác, nhưng điều đó có thể được khắc phục bằng một séc khác). Ngay cả khi đó, nếu bạn thực sự muốn so sánh, thì tốt hơn hết là bạn nên làmtypeid(n) == typeid(int)
Zoe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.