C++中std::is_object的具体使用
作者:十五年专注C++开发
1.概述
std::is_object是一种C++类型特性,其用途是判断一个类型是否是一个对象类型(除了函数、引用和void类型)。如下例子:
#include <iostream> #include <type_traits> class A {}; int main() { std::cout << std::boolalpha; std::cout << "is_object:" << std::endl; std::cout << "int: " << std::is_object<int>::value << std::endl; //输出:true std::cout << "A: " << std::is_object<A>::value << std::endl; //输出:true std::cout << "A&: " << std::is_object<A&>::value << std::endl; //输出:false std::cout << "A*: " << std::is_object<A*>::value << std::endl; //输出:true std::cout << "int(int): " << std::is_object<int(int)>::value << std::endl; //输出:false std::cout << "int(*)(int): " << std::is_object<int(*)(int)>::value << std::endl; //输出: // true return 0; }
2.原理分析
2.1.std::is_object
std::is_object的源码如下:
template <class _Ty> constexpr bool is_object_v = !is_function_V<_Ty> && !is_reference_v<_Ty> && !is_void_v<_Ty>; template <class _Ty> struct is_object : bool_constant<is_object_v<_Ty>> {};
is_function_v<T> : 判断是否检查 T 是否为函数类型。如 std::function 、 lambda 、有重载 operator() 的类和指向函数指针不是函数类型。若 T 为函数类型,则提供等于 true 的成员常量 value 。否则, value 等于 false, 示例如下:
#include <type_traits> using namespace std; struct GeeksforGeeks { int func() const&; }; template <typename> struct Computer { }; template <class A, class B> struct Computer<B A::*> { using member_type = B; }; int x1(); int main() { cout << is_function<int(int)>::value << endl; //输出:true cout << is_function<GeeksforGeeks>::value << endl; //输出:false cout << is_function<int>::value << endl; //输出:false cout << is_function<decltype(x1)>::value << endl; //输出:true using A = Computer<decltype( &GeeksforGeeks::func)>::member_type; cout << is_function<A>::value << endl; //输出:true return 0; }
is_reference_v<T> : 若 T 是引用类型(左值引用或右值引用),则提供等于 true 的成员常量 value 。对于任何其他类型, value 为 false; 示例如下:
#include <iostream> #include <type_traits> using namespace std; class MyTest { }; int main() { cout << "\n class TP : "<<is_reference<MyTest>::value; //输出:false cout << "\n class TP&: "<<is_reference<MyTest&>::value; //输出:true cout << "\n class TP&&: "<<is_reference<MyTest&&>::value; //输出:true return 0; }
is_void_v<T> : 检查 T 是否为 void 类型。若 T 是类型 void 、 const void 、 volatile void 或 const volatile void ,则提供等于 true 的成员常量 value。否则, value 等于 false; 示例如下:
#include <iostream> #include <type_traits> int main() { std::cout << std::boolalpha; std::cout << std::is_void<void>::value << '\n'; //输出:true std::cout << std::is_void<int>::value << '\n'; //输出:false }
2.2.bool_constant
bool_constant是integral_constant<bool, _Val>的别名,从下面的定义可以看出:
template <bool _Val> using bool_constant = integral_constant<bool, _Val>; using true_type = bool_constant<true>; using false_type = bool_constant<false>;
那么integral_constant的定义呢?继续看下面:
template <class _Ty, _Ty _Val> struct integral_constant { static constexpr _Ty value = _Val; using value_type = _Ty; using type = integral_constant; constexpr operator value_type() const noexcept { return value; } _NODISCARD constexpr value_type operator()() const noexcept { return value; } };
std::integral_constant包装特定类型的静态常量,它是C++类型特征的基类。我们可以看到,这个模板类接受两个参数,一个类型_Ty和一个该类型的值_Val。它提供了一个静态的常量成员value,该成员的值就是传入的_Val;其中,using value_type = _Ty;和using type = integral_constant;分别用来定义value的类型以及integral_constant本身的类型。
然后,它还提供了两个转换函数,一个是constexpr operator value_type() const noexcept,可以将std::integral_constant对象隐式转换为T类型的值;另一个是constexpr value_type operator()() const noexcept,可以将std::integral_constant对象当作函数来调用,并返回其内部保存的常量。
std::integral_constant 的两个最常用的特化版本是 std::true_type 和 std::false_type。它们是 std::integral_constant<bool, value> 的特化版本,其中 std::true_type 是 std::integral_constant<bool, true>,std::false_type 是 std::integral_constant<bool, false>。这两种类型的主要用途是表示编译期的布尔值。在模板元编程中,它们常被用来代表一种编译期的"是"和"否",从而允许我们进行编译期的条件判断。同时,由于它们都是类型,因此也可以作为类型标签来使用,帮助我们在模板元编程中传递信息。
通过这样的设计,std::integral_constant能够让我们在编译期间就能确定某些值,从而提高代码的效率。同时,因为它包含了值类型的信息,我们还可以根据这个信息进行编程,提高代码的灵活性。
通过上述的解释和分析,我们可以很清楚的理解了std::is_object的含义了。
3.使用
std::is_object主要用于元编程中的类型检查,以便在编译时确定某个类型是否符合限制条件。使用方法也比较简单,只需在代码中调用std::is_object<>模板,并传入要检查的类型名,即可获得该类型是否为对象类型的结果。示例如下:
template <typename T> void calc(){ static_assert(std::is_object<T>::value, "T must be an object type."); //... } class MyTest{}; int main(){ calc<int>(); MyTest x; func<decltype(x)>(); calc<int&>(); //compile error return 0; }
上述代码中,定义了一个模板函数calc,该函数要求其参数类型必须是对象类型。在模板函数中使用了std::is_object<>模板,来检查模板参数类型是否为对象类型。如果不是,将会抛出一个编译器错误。这样,就能够在编译期间检测到错误的使用,减少运行时错误的概率。
使用注意:1)std::is_object判断的是类型是否为对象类型,而非是否为类类型或枚举类型。 2)使用std::is_object模板时,需要注意传入的类型名中不要包含已删除的引用和cv限定符。示例如下:
#include<iostream> #include<type_traits> struct MyStruct{}; enum class MyEnum{A,B}; int main(){ std::cout << std::is_object<MyStruct>::value << std::endl; //true std::cout << std::is_object<MyEnum>::value << std::endl; //true std::cout << std::is_object<int>::value << std::endl; //true std::cout << std::is_object<const int>::value << std::endl; //true std::cout << std::is_object<const int&>::value << std::endl; //false std::cout << std::is_object<const volatile int>::value << std::endl; //true return 0; }
4.总结
std::is_object是一个用于元编程的C++类型特性,用于判断一个类型是否是对象类型。只需在代码中调用std::is_object<>模板,并传入要检查的类型名,即可判断该类型是否为对象类型。在编写代码时,需要注意std::is_object判断的是类型是否为对象类型,而不是类类型或枚举类型。同时,在使用std::is_object模板进行类型检查时,需要注意传入的类型名中不要包含已删除的引用和cv限定符。通过合理使用std::is_object模板,可以在编译期间检测到错误的使用,减少运行时错误的概率,提高代码稳定性。
到此这篇关于C++中std::is_object的具体使用的文章就介绍到这了,更多相关C++ std::is_object内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!