Как мне узнать тип переменной?

131

В C ++ как найти тип переменной?

0x499602D2
источник
5
Возможный дубликат stackoverflow.com/questions/81870/print-variable-type-in-c
самый суровый
7
cout << typeid (переменная) .name () << endl;
SRN
2
Используйте поиск или гугл :) stackoverflow.com/questions/81870/print-variable-type-in-c Самый резкий - быстрый: D
Карибу
14
@Kariboo, я использовал Google, и он отправил меня сюда.
Майкл Уорнер,
Этот вопрос очень неясен сам по себе, и даже после того, как увидел различные ответы; отнюдь не ясно, ищет ли вопрос общепринятый ответ.
Антти Хаапала

Ответы:

159

Вы можете использовать оператор typeid :

#include <typeinfo>
...
cout << typeid(variable).name() << endl;
Рич О'Келли
источник
15
@David - iзначит целое число в вашем компиляторе. Возвращаемые имена не указаны стандартом.
Bo Persson
11
Когда я использую его в vector <int>, он возвращает St6vectorIiSaIiEE. WTF?
Боян Кушлев
2
@BobbyBrown, ты не одинок !! google.co.uk/webhp#safe=off&q=St6vectorIiSaIiEE
Рич О'Келли,
5
Имена, возвращаемые функцией typeid, очень сокращены, зависят от компилятора и не предназначены для использования человеком. Вы можете «разобрать» их (это настоящий термин!), Либо в коде с помощью чего-то вроде gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html , с помощью таких утилит командной строки, как c++filt, либо с помощью любого из различных онлайн-деманглеров например, demangler.com .
cincodenada
33

Для статических утверждений введен C ++ 11, decltypeкоторый весьма полезен в определенных сценариях.

Nae
источник
12

Если у вас есть переменная

int k;

Вы можете получить его тип, используя

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

См. Следующую ветку на SO: Аналогичный вопрос

Amit
источник
9

Основное различие между C ++ и Javascript заключается в том, что C ++ - это язык со статической типизацией, а javascript - динамический.

В языках с динамической типизацией переменная может содержать что угодно, и ее тип задается значением, которое она содержит, момент за моментом. В языках со статической типизацией тип переменной объявлен и не может быть изменен.

Может быть динамическая диспетчеризация и составление объектов и подтипирование (наследование и виртуальные функции), а также статическая диспетчеризация и супертипирование (через шаблон CRTP), но в любом случае тип переменной должен быть известен компилятору.

Если вы в состоянии не знать, что это такое или может быть, то это потому, что вы что-то спроектировали, поскольку язык имеет динамическую систему типов.

Если это так, вам лучше переосмыслить свой дизайн, поскольку он идет в землю, не естественную для используемого вами языка (больше всего похоже на движение по автостраде с гусеницей или по воде на машине).

Эмилио Гаравалья
источник
Если в C ++ есть динамическое изменение, я думаю, это было бы здорово, и функции typeof и parseInt, parseFloat также пригодятся, но я не знаю, почему разработчики C ++ делают это слишком сложно, например! кто говорит, что хорошо писать cout << "String"
Вакас Тахир
решительность самая лучшая !!!! #include <поток> строка str ("1912"); int strtointval; stringstream (str) >> strtointval;
Вакас Тахир,
@Waqas Что? Люди, которые говорят, что это лучше всего, - это люди, которые определяют язык, и, IMO, они в значительной степени имеют последнее слово во всем, что с ним связано - например, о хороших методах кодирования. Не могли бы вы перефразировать этот комментарий, чтобы он имел больше смысла?
Иск Фонда Моники
Я полностью не согласен. Java, C #, PHP, Perl, Python и другие были разработаны на C и C ++ и не являются гусеницами. (Когда вы создаете приложение базы данных для открытия таблиц переменных из «неизвестных» баз данных, вам нужно управлять типом поля в соответствии со схемой переменных и наоборот «очень» динамичным способом;))
TomeeNS
@TomeeNS: Нет. Они написаны на C и C ++, а не разработаны . Они созданы для того, чтобы делать свою работу. У них есть динамический тип, даже если сами C и C ++ этого не делают. В этом нет ничего странного.
Эмилио Гаравалья
8

Обычно поиск типа переменной в C ++ - неправильный вопрос. Обычно это что-то, что вы носите с собой из процедурных языков, таких как, например, C или Pascal.

Если вы хотите закодировать разное поведение в зависимости от типа, попробуйте узнать, например, о перегрузке функций и наследовании объектов . Это не будет иметь смысла сразу после вашего первого дня изучения C ++, но продолжайте.

Pontus Gagge
источник
Не совсем, допустим, у вас есть класс Object и подкласс Book. Теперь представьте, что у вас есть Коробка, в которой может храниться множество объектов, но по какой-то причине вы хотите перечислить все книги внутри нее. Проверка типа намного чище, чем необходимость добавить метод «type» в Object, а затем переопределить его в Book, чтобы вернуть что-то вроде «book»
Пауло Сезар
Как и в любом правиле, есть исключения (отсюда и мое «обычно»!), А контейнеры, как правило, усложняют теорию типов. Я никогда не слишком увлекался контейнерами-полиморфными-объектами… в большинстве случаев достаточно шаблонных универсальных типов контейнеров, которые намного чище.
Pontus Gagge
Вы не пользуетесь шаблонами?
Брайан Грейс
6

Я считаю, что у меня есть допустимый вариант использования typeid (), так же как и sizeof (). Для функции шаблона мне нужен специальный код, основанный на переменной шаблона, чтобы я предлагал максимальную функциональность и гибкость.

Создание одного экземпляра функции для каждого поддерживаемого типа намного компактнее и удобнее, чем использование полиморфизма. Даже в этом случае я мог бы использовать этот трюк, чтобы написать тело функции только один раз:

Обратите внимание: поскольку в коде используются шаблоны, приведенный ниже оператор switch должен статически разрешаться только в один блок кода, оптимизируя все ложные случаи, AFAIK.

Рассмотрим этот пример, где нам может потребоваться обработать преобразование, если 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 () является проверкой во время выполнения , а не во время компиляции, поэтому его нельзя использовать для генерации оптимизированного кода.
Дэн Чыонг
1
Да, нет, это не то, что вы думали. typeidпросто не может быть статической проверкой во время компиляции - по определению - так что это не способствует какой-либо оптимизации. For a template function, I need to special case the code based on the template variableИтак, что вам действительно нужно, так это статический полиморфизм через идиому CRTP. Именно это и достигается.
underscore_d
4

Не уверен, что мой ответ поможет.

Короткий ответ: вам действительно не нужно / не нужно знать тип переменной для ее использования.

Если вам нужно указать тип статической переменной, вы можете просто использовать auto.

В более сложном случае, когда вы хотите использовать «auto» в классе или структуре, я бы предложил использовать шаблон с decltype.

Например, предположим, что вы используете чью-то библиотеку и в ней есть переменная с именем «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);
}

Это все еще немного утомительно, но это максимально близко к безтиповым языкам. Просто убедитесь, что всякий раз, когда вы ссылаетесь на переменную шаблона, всегда помещайте туда спецификацию шаблона.

gohongyi
источник
2
#include <typeinfo>

...
string s = typeid(YourClass).name()
радиан
источник
0

Если вам нужно провести сравнение между классом и известным типом, например:

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

Вы можете использовать эту строку сравнения:

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

который проверяет, что typeidимя содержит тип строки (имя typeid имеет другие искаженные данные, поэтому лучше использовать a s1.find(s2)вместо ==).

jackw11111
источник
-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;
}

Обратите внимание, как работают первый и второй оба варианта.

Pikachu
источник
Распознавать тип по первому символу - очень плохая идея.
Дмитрий Кузьминов
Подскажите подробнее, Дмитрий? Я не понял твою точку зрения.
Пикачу
Это можно просто сократить до std::cout << "I'm a variable of type " << typeid(n).name(). (изменен, чтобы предотвратить появление артефактов, но это можно исправить с помощью другой проверки). Даже в этом случае, если вам абсолютно необходимо сравнение, это намного лучше сделатьtypeid(n) == typeid(int)
Зои