【问题标题】:How can I compare types in C++?如何比较 C++ 中的类型?
【发布时间】:2020-11-17 22:04:55
【问题描述】:

有没有办法比较 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 中使用 Script 包的以下简单代码中使用它时,它会运行。

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

编辑 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);
            }
        }
    }
}

【问题讨论】:

  • std::is_same&lt;T, int&gt;::value?
  • Algirdas 是对的,而且更进一步 - 如果你想在 if 语句中做一些只会为测试的特定类型编译的事情,你可以做类似 if constexpr (std::is_same_v&lt;T, int&gt;) std::cout &lt;&lt; "I can can add 2 to " &lt;&lt; variable &lt;&lt; " to get " &lt;&lt; variable + 2 &lt;&lt; std::endl; 的事情 - 那不会如果Tstd::string,则不会出现编译器错误。 (is_same_v 助手让您不必附加 ::value)。
  • std::is_same&lt;T, int&gt;::value 会为这个确切的问题提供一个很好的布尔值,但在实践中并不是特别常见,因为还有很多其他事情可以与其他事情一起进行类型比较,并选择正确的工具需要背景和对更广泛问题的看法。那么……你真正要解决的是什么
  • 我有一个自己制作的LinkedList类,我想根据模板传递的List类型做一个排序算法。
  • 错误是什么?

标签: c++ variables typeof typeid


【解决方案1】:

查看 EDIT 2 中的代码,您可能希望使用 if constexpr 代替(假设 C++17 兼容编译器)。这里的问题是,通常编译器需要对 if 语句的所有分支的代码进行语法检查,即使从逻辑上讲,对于给定的模板实例化可能只采用一个分支。

if constexpr 放宽了这一要求:未采用的分支被“丢弃”,这意味着如果未采用该分支,则取决于模板参数的值不会被实例化。这意味着它永远不会尝试做,例如,当keytypeint 时,k.at(0),因为在这种情况下我们不会进入那个分支。

假设您的编译器支持 C++17(并且启用了该标准!),将代码中的所有 if 替换为 if constexpr 应该可以解决此特定问题。

【讨论】:

  • 如何启用它?它向我返回警告:Consexpr 是 C++17 扩展。
  • @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 << "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

在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 << "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

【讨论】:

  • 我已经在 Atom 中尝试过,正如帖子所说,它有效。问题是它在 Xcode 中不起作用。
  • 那么你将不得不更具体地了解 WHAT 不完全有效
  • 给出的错误是: - 成员引用基类型 'int' 不是结构或联合 - 成员引用基类型 'char' 不是结构或联合
【解决方案3】:

在 C++ 中有 typeid() 运算符,它返回一个 std::type_info,这可以通过多种方式使用。

你像这样使用std::type_info::hash_code()

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

或者,您可以像这样使用std::type_info::name()

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

请注意后者,如果您输入std::string 之类的内容,您最终会得到类似class std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; 的输出内容。这只是因为 std::stringusingclass std::basic_string&lt;char,struct std::char_traits&lt;char&gt;,class std::allocator&lt;char&gt; &gt; 定义的。

编辑:我忘了说,你需要一个#include &lt;typeinfo&gt; 才能使用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 参数除以向量的分配数。

    【讨论】:

    • 这对内置类型也不起作用。当structs 和classes 发挥作用时,这将更有效。 sizeof 不是每个类型唯一的。
    • Sizeof 确实以字节为单位返回变量的长度。因此,如果您输入 sizeof(char 变量),它将为任何不依赖于其内容的 char 变量返回 1 个字节。使用向量,它将返回其类型大小乘以分配数量。其他类型也一样。
    • 给定std::vector&lt;int&gt; little = {1, 2, 3}; std::vector&lt;int&gt; 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)。但是foo1foo2 是非常不同的类型。您的解决方案不起作用。
    • sizeof(bool) == sizeof(char) 因此您无法仅根据大小来区分它们。与(u)int16_t(unsigned) short(u)int32_t(unsigned) int 等相同。类型不同,但它们可以具有相同的大小。
    猜你喜欢
    • 2015-02-10
    • 2023-03-26
    • 2012-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    • 2014-08-19
    相关资源
    最近更新 更多