#c #variables #typeof #typeid
#c #переменные #typeof #typeid
Вопрос:
есть ли способ сравнить типы переменных в C ? Например, я хочу что-то, что работает следующим образом: (используя псевдоязык)
template <class T> void checkType(T variable) {
if(type_of(T) == int) cout << "The variable is of type int.n";
}
РЕДАКТИРОВАТЬ 1: я пытался использовать is_same, но это не сработало в Xcode … но когда я пытаюсь использовать его в следующем простом коде в Atom, используя пакет сценариев, он запускается.
#include <iostream>
using namespace std;
template <class T> void print(T value) {
if(is_same<T, char> :: value) cout << "charn";
if(is_same<T, int> :: value) cout << "intn";
if(is_same<T, string> :: value) cout << "stringn";
}
int main() {
string var1;
int var2;
char var3;
print(var1);
print(var2);
print(var3);
return 0;
}
РЕДАКТИРОВАТЬ 2: я размещаю здесь код, который не работает. Теперь я попытался прокомментировать часть, касающуюся строк, и код работает для int и char .
template <class keytype, class attrtype>
void LinkedList <keytype, attrtype> :: insert(keytype k, attrtype a) {
LinkedList <keytype, attrtype> :: position iter = l.head();
if(is_same<keytype, int> :: value) {
while(iter != NULL and k > iter -> key) {
iter = l.next(iter);
}
l.insert(iter, k, a);
}
else if(is_same<keytype, char> :: value) {
while(iter != NULL and tolower(k) > tolower(iter -> key)) {
iter = l.next(iter);
}
l.insert(iter, k, a);
}
//Whatever type I pass by the template in 'keytype' enters this if statement
else if(is_same<keytype, string> :: value) {
bool node_filled = false;
if(iter == NULL) {
l.insert(iter, k, a);
node_filled = true;
}
else {
unsigned long rif = 0;
int i = 0;
while(!node_filled and iter != NULL) {
if(tolower(iter -> key.at(0)) > tolower(k.at(0))) {
l.insert(iter, k, a);
node_filled = true;
}
else if(tolower(iter -> key.at(0)) < tolower(k.at(0))) {
iter = l.next(iter);
}
else if(tolower(iter -> key.at(0)) == tolower(k.at(0))) {
if(k.size() > iter -> key.size())
rif = iter -> key.size();
else
rif = k.size();
while((i < rif - 1) and (k.at(i) == iter -> key.at(i))) {
i ;
}
if(tolower(iter -> key.at(i)) > tolower(k.at(i))) {
l.insert(iter, k, a);
node_filled = true;
}
else if(tolower(iter -> key.at(i)) == tolower(k.at(i))) {
if(k.size() < iter -> key.size()) {
l.insert(iter, k, a);
node_filled = true;
}
else {
iter = l.next(iter);
}
}
else if(tolower(iter -> key.at(i)) < tolower(k.at(i))) {
iter = l.next(iter);
}
}
}
if(!node_filled) {
l.insert(NULL, k, a);
}
}
}
}
Комментарии:
1.
std::is_same<T, int>::value
?2. Альгирдас прав, и далее — если вы хотите сделать что-то в
if
инструкции, что будет компилироваться только для определенного проверяемого типа, вы можете сделать что-то вродеif constexpr (std::is_same_v<T, int>) std::cout << "I can can add 2 to " << variable << " to get " << variable 2 << std::endl;
— это не приведет к ошибке компилятора, еслиT
, скажемstd::string
. (is_same_v
Помощник избавляет вас от необходимости добавлять::value
).3.
std::is_same<T, int>::value
это дало бы хорошее логическое значение для этого точного вопроса, но на практике это не особенно часто делается, потому что есть так много других вещей, которые сравнивают типы вместе с чем-то еще, и выбор правильного инструмента требует контекста и представления более широкой проблемы. Итак … что вы на самом деле решаете ?4. У меня есть класс LinkedList, созданный мной, и я хочу создать алгоритм сортировки на основе типа списка, передаваемого через шаблон.
5. В чем ошибка?
Ответ №1:
Глядя на код в ПРАВКЕ 2, вы можете захотеть использовать if constexpr
его вместо этого (при условии, что компилятор, совместимый с C 17). Проблема здесь в том, что обычно компилятору необходимо проверять синтаксис вашего кода для всех ветвей оператора if, даже если логически для создания данного экземпляра шаблона может быть использована только одна ветвь.
if constexpr
ослабляет это требование: неиспользованная ветвь «отбрасывается», что означает, что значения, зависящие от аргументов шаблона, не создаются, если ветвь не используется. Это означает, что он никогда не будет пытаться выполнить, например, k.at(0)
when keytype
is an int
, поскольку мы не будем вводить эту ветку, если это так.
Предполагая, что ваш компилятор поддерживает C 17 (и этот стандарт включен!), Замена всех if
с if constexpr
в вашем коде должна устранить эту конкретную проблему.
Комментарии:
1. Как я могу это включить? Он возвращает мне предупреждение: Constexpr является расширением C 17.
2. @K0sm Вы упомянули, что используете XCode; Я не знаком с IDE, но, предполагая, что Clang является компилятором, вы должны решить, как передать
-std=c 17
компилятору.
Ответ №2:
Это работает для меня.
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
template <class T>
void print(T value) {
if (is_same<T, char>::value) cout << "charn";
if (is_same<T, int>::value) cout << "intn";
if (is_same<T, string>::value) cout << "stringn";
}
int main() {
string var1;
int var2;
char var3;
print(var1);
print(var2);
print(var3);
return 0;
}
В C 17 вы можете использовать if constexpr
, чтобы позволить компилятору генерировать более оптимальный codegen:
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
template <class T>
void print(T value) {
if constexpr (is_same_v<T, char>) cout << "charn";
if constexpr (is_same_v<T, int>) cout << "intn";
if constexpr (is_same_v<T, string>) cout << "stringn";
}
int main() {
string var1;
int var2;
char var3;
print(var1);
print(var2);
print(var3);
return 0;
}
Комментарии:
1. Я уже пробовал это в Atom и, как говорится в сообщении, это сработало. Проблема в том, что это не работает в Xcode.
2. Тогда вам нужно будет более конкретно указать, ЧТО именно не работает
3. Приведенные ошибки: — Ссылочный базовый тип элемента ‘int’ не является структурой или объединением и — Ссылочный базовый тип элемента ‘char’ не является структурой или объединением
Ответ №3:
В C есть typeid()
оператор, который возвращает a std::type_info
, это можно использовать несколькими способами.
Вы используете std::type_info::hash_code()
так:
template<typename T>
void print()
{
if (typeid(T).hash_code() == typeid(char).hash_code())
std::cout << "charn"
else if (typeid(T).hash_code() == typeid(int).hash_code())
std::cout << "intn"
else if (typeid(T).hash_code() == typeid(std::string).hash_code())
std::cout << "std::stringn"
}
или вы могли бы использовать std::type_info::name()
так:
template<typename T>
void print()
{
std::cout << typeid(T) << 'n';
}
Просто будьте осторожны с последним, что если вы поместите что-то вроде std::string
, вы получите что-то вроде class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
для вывода. Это просто потому std::string
using
, что это определение для class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
.
Редактировать: я забыл сказать, вам нужно #include <typeinfo>
использовать std::type_info
.
Ответ №4:
Вы можете попробовать это:
template <class T> void checkType(T variable) {
switch(sizeof(T)){
case sizeof(int) :
cout << "The variable is of type int.n";
break;
case sizeof(char):
cout << "The variable is of type char.n";
break;
}
}
Наблюдение: если у вас есть вектор, вам нужно будет дать ему специальную обработку, разделив его sizeof int параметр switch на количество выделений вектора, например.
Комментарии:
1. Это не будет работать даже для встроенных типов. Когда
struct
s иclass
es вступают в игру, это будет работать еще меньше.sizeof
не является уникальным для каждого типа.2. Sizeof возвращает значение переменной в байтах. Итак, если вы введете sizeof(переменную char), она вернет 1 байт для любой переменной char, не зависящей от ее содержимого. И с помощью vectors он вернет размер своего типа, умноженный на количество выделений. То же самое для других типов.
3. Учитывая
std::vector<int> little = {1, 2, 3}; std::vector<int> large = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
,sizeof(little) == sizeof(large)
, так что вы ошибаетесь здесь. Другой пример:struct foo1{ int x; }; struct foo2 { short s1; short s2; };
. Предполагая, чтоshort
это 2 байта иint
4 байта,sizeof(foo1) == sizeof(foo2)
. Ноfoo1
иfoo2
очень разные типы. Ваше решение не работает.4.
sizeof(bool) == sizeof(char)
таким образом, вы не сможете различать их только по размеру. То же самое с(u)int16_t
и(unsigned) short
,(u)int32_t
и т.д.(unsigned) int
Разные типы, но они могут иметь одинаковые размеры.