简体   繁体   中英

How can I compare types in C++?

is there a way to compare types of variables in C++? For example, I want something that works like this: (using pseudolanguage)

template <class T> void checkType(T variable) {
    if(type_of(T) == int) cout << "The variable is of type int.\n";
}

EDIT 1: I tried to use is_same, but it didn't work in Xcode...but when I try to use it in the following simple code in Atom using Script package it runs.

#include <iostream>

using namespace std;

template <class T> void print(T value) {
  if(is_same<T, char> :: value) cout << "char\n";
  if(is_same<T, int> :: value) cout << "int\n";
  if(is_same<T, string> :: value) cout << "string\n";
}

int main() {
  string var1;
  int var2;
  char var3;

  print(var1);
  print(var2);
  print(var3);

  return 0;
}

EDIT 2: I place here the code that doesn't work. Now I tried to comment the part regarding strings and the code works for int and 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);
            }
        }
    }
}

Looking at the code in EDIT 2, you may want to use if constexpr there instead (assuming a C++17-compliant compiler). The issue here is that normally the compiler will need to syntax check your code for all branches of the if statement, even if logically only one branch could possibly be taken for a given template instantiation.

if constexpr relaxes this requirement: the untaken branch is "discarded", which means that values depending on the template arguments are not instantiated if the branch is not taken. This means that it will never try to do, for example, k.at(0) when keytype is an int , since we will not enter that branch if that is the case.

Assuming your compiler supports C++17 (and that standard is enabled!), replacing all the if with if constexpr in your code should fix this particular issue.

This work for me.

#include <iostream>
#include <string>
#include <type_traits>

using namespace std;

template <class T>
void print(T value) {
  if (is_same<T, char>::value) cout << "char\n";
  if (is_same<T, int>::value) cout << "int\n";
  if (is_same<T, string>::value) cout << "string\n";
}

int main() {
  string var1;
  int var2;
  char var3;

  print(var1);
  print(var2);
  print(var3);

  return 0;
}

Live Demo

In C++17, you can use if constexpr to let the compiler generate more optimal 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 << "char\n";
  if constexpr (is_same_v<T, int>) cout << "int\n";
  if constexpr (is_same_v<T, string>) cout << "string\n";
}

int main() {
  string var1;
  int var2;
  char var3;

  print(var1);
  print(var2);
  print(var3);

  return 0;
}

Live Demo

In C++ there is the typeid() operator which returns a std::type_info , this can be used in a couple of ways.

You use std::type_info::hash_code() like this:

template<typename T>
void print()
{
    if (typeid(T).hash_code() == typeid(char).hash_code())
        std::cout << "char\n"
    else if (typeid(T).hash_code() == typeid(int).hash_code())
        std::cout << "int\n"
    else if (typeid(T).hash_code() == typeid(std::string).hash_code())
        std::cout << "std::string\n"
}

or, you could use std::type_info::name() like this:

template<typename T>
void print()
{
    std::cout << typeid(T) << '\n';
}

Just beware with the latter that if you put something like std::string , you will end up with something like class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > for an output. That's just because std::string is a using define for class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > .

Edit: I forgot to say, you need a #include <typeinfo> to use std::type_info .

You can try this:

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

Observation: if you have a vector you will have to give it a special treatment by dividing it sizeof int the switch parameter by the number of allocations of the vector for example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM