目录
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;
}
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
}
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的含义了。
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;
}
std::is_object是一个用于元编程的C++类型特性,用于判断一个类型是否是对象类型。只需在代码中调用std::is_object<>模板,并传入要检查的类型名,即可判断该类型是否为对象类型。在编写代码时,需要注意std::is_object判断的是类型是否为对象类型,而不是类类型或枚举类型。同时,在使用std::is_object模板进行类型检查时,需要注意传入的类型名中不要包含已删除的引用和cv限定符。通过合理使用std::is_object模板,可以在编译期间检测到错误的使用,减少运行时错误的概率,提高代码稳定性。