解释c++中的decltype,typeid和typeof关键字的作用和用法,以及它们之间的区别。
decltype:
这是C++11引入的一个关键字,它可以根据一个表达式的类型和值类别推导出一个类型。它常用于声明一些难以用标准语法表示的类型,例如lambda表达式的类型或者依赖于模板参数的类型。它也可以用于保留一个表达式的引用性和常量性,例如返回类型后置语法或者decltype(auto)的用法。
decltype的用法是在一个表达式前加上decltype关键字,例如decltype(x),它会返回x的类型。如果表达式是一个括号包围的左值,
例如decltype((x)),它会返回x的左值引用类型。decltype的规则有时候会比较复杂
typeid
这是C++98就有的一个运算符,它可以返回一个表达式或者一个类型的std::type_info对象的引用,该对象包含了类型的名称和其他信息。它常用于运行时的类型识别,例如判断一个对象的动态类型或者比较两个类型是否相同。typeid的用法是在一个表达式或者一个类型前加上typeid运算符,例如typeid(x)或者typeid(int),它会返回一个std::type_info对象的引用。如果表达式是一个多态类型的对象或者指针,typeid会返回该对象的动态类型,否则返回静态类型。typeid的结果可以用name()成员函数来获取类型的名称,但是这个名称是由编译器实现定义的,不一定是可读的或者一致的。您可以参考这个网页²来了解更多的细节和例子。
typeof
这是一个非标准的关键字,它在一些编译器中提供了类似于decltype的功能,即根据一个表达式的类型推导出一个类型。它的用法是在一个表达式前加上typeof关键字,例如typeof(x),它会返回x的类型。它和decltype的区别是,typeof不会区分左值和右值,也不会保留引用性和常量性。typeof也不是C++标准的一部分,所以不建议在可移植的代码中使用它。您可以参考这个网页³来了解更多的细节和例子。
以上是我为您解释的c++中的decltype,typeid和typeof关键字的作用和用法
(1) Is it possible to print a variable's type in standard C++?. https://stackoverflow.com/questions/81870/is-it-possible-to-print-a-variables-type-in-standard-c.
(2) decltype specifier - cppreference.com. https://en.cppreference.com/w/cpp/language/decltype.
(3) typeid operator - cppreference.com. https://en.cppreference.com/w/cpp/language/typeid.
(4) decltype and typeid returns different type - Stack Overflow. https://stackoverflow.com/questions/50424102/decltype-and-typeid-returns-different-type.
一些在代码中使用decltype,typeid和typeof关键字的场景和示例
但请注意,这些关键字并不是C语言标准的一部分,而是C++或者GNU C的特性,所以您可能需要使用相应的编译器和语言模式来编译和运行您的代码。
- decltype:这个关键字可以用来在编译时推导出一个表达式的类型,它常用于以下几种场景:
- 声明一个变量,但不知道它的确切类型,只知道它和另一个表达式的类型相同,例如:
auto x = some_function(); // x的类型由some_function的返回值决定 decltype(x) y = x; // y的类型和x的类型相同
- 声明一个函数的返回类型,但不知道它的确切类型,只知道它和函数体中某个表达式的类型相同,例如:
template<typename T, typename U> auto add(T t, U u) -> decltype(t + u) // 返回类型由t + u的类型决定 { return t + u; }
- 声明一个模板参数的类型,但不知道它的确切类型,只知道它和模板类或函数中某个表达式的类型相同,例如:
template<typename Container> void print_elements(const Container& c) { for (auto it = c.begin(); it != c.end(); ++it) { decltype(*it) x = *it; // x的类型和容器中的元素类型相同 std::cout << x << " "; } std::cout << std::endl; }
- 声明一个变量,但不知道它的确切类型,只知道它和另一个表达式的类型相同,例如:
- typeid:这个运算符可以用来在运行时获取一个表达式或者一个类型的类型信息,它常用于以下几种场景:
- 判断一个对象的动态类型,即运行时的实际类型,而不是静态类型,即编译时的声明类型,例如:
class Base { virtual void foo() {} }; class Derived : public Base {}; Base* p = new Derived(); std::cout << typeid(p).name() << std::endl; // 输出Base* std::cout << typeid(*p).name() << std::endl; // 输出Derived
- 比较两个表达式或者类型是否相同,例如:
int x = 0; double y = 0.0; std::cout << std::boolalpha; std::cout << (typeid(x) == typeid(y)) << std::endl; // 输出false std::cout << (typeid(x) == typeid(int)) << std::endl; // 输出true
- 获取一个表达式或者类型的名称,但是这个名称是由编译器实现定义的,不一定是可读的或者一致的,例如:
std::cout << typeid(std::string).name() << std::endl; // 输出std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
- 判断一个对象的动态类型,即运行时的实际类型,而不是静态类型,即编译时的声明类型,例如:
- typeof:这个关键字可以用来在编译时推导出一个表达式的类型,它常用于以下几种场景:
- 声明一个变量,但不知道它的确切类型,只知道它和另一个表达式的类型相同,例如:
int x = 0; typeof(x) y = x; // y的类型和x的类型相同
- 声明一个函数的返回类型,但不知道它的确切类型,只知道它和函数体中某个表达式的类型相同,例如:
int foo(); typeof(foo()) bar(); // bar的返回类型和foo的返回类型相同
- 声明一个模板参数的类型,但不知道它的确切类型,只知道它和模板类或函数中某个表达式的类型相同,例如:
template<typename T> struct Node { T data; typeof(data)* next; // next的类型和data的类型相同 };
- 声明一个变量,但不知道它的确切类型,只知道它和另一个表达式的类型相同,例如: