1 type_traits 复合类型特性
1.1 std::is_function
std::is_function 是一个模板类,用于检查一个类型是否为函数类型。
定义:
cpp
template< class T >
struct is_function;
当 T 为函数类型则为 true,否则为 false。
样例:
cpp
#include <iostream>
#include <type_traits>
int myFunction() { return 0; }
int main() {
std::cout << std::boolalpha;
std::cout << "myFunction is " << std::is_function<decltype(myFunction)>::value << '\n'; // 输出 true
std::cout << "int is " << std::is_function<int>::value << '\n'; // 输出 false
return 0;
}
1.2 std::is_class
std::is_class 是一个模板类,用于检查一个类型是否为类类型(不包括联合体)。
定义:
cpp
template< class T >
struct is_class;
当 T 为类类型(不包括联合体)则为 true,否则为 false。
样例:
cpp
#include <iostream>
#include <type_traits>
struct MyClass {};
union MyUnion {};
int main() {
std::cout << std::boolalpha;
std::cout << "MyClass is " << std::is_class<MyClass>::value << '\n'; // 输出 true
std::cout << "MyUnion is " << std::is_class<MyUnion>::value << '\n'; // 输出 false
std::cout << "int is " << std::is_class<int>::value << '\n'; // 输出 false
return 0;
}
1.3 std::is_union
std::is_union 是一个模板类,用于检查一个类型是否为联合体(union)类型。
定义:
cpp
template< class T >
struct is_union;
当 T 为联合体类型则为 true,否则为 false。
样例:
cpp
#include <iostream>
#include <type_traits>
struct MyClass {};
union MyUnion {};
int main() {
std::cout << std::boolalpha;
std::cout << "MyClass is " << std::is_union<MyClass>::value << '\n'; // 输出 false
std::cout << "MyUnion is " << std::is_union<MyUnion>::value << '\n'; // 输出 true
std::cout << "int is " << std::is_union<int>::value << '\n'; // 输出 false
return 0;
}
1.4 std::is_enum
std::is_enum 是一个模板类,用于检查一个类型是否为枚举类型。
定义:
cpp
template< class T >
struct is_enum;
当 T 为枚举类型则为 true,否则为 false。
样例:
cpp
#include <iostream>
#include <type_traits>
enum MyEnum { ENUM_VALUE };
int main() {
std::cout << std::boolalpha;
std::cout << "MyEnum is " << std::is_enum<MyEnum>::value << '\n'; // 输出 true
std::cout << "int is " << std::is_enum<int>::value << '\n'; // 输出 false
return 0;
}
1.5 std::is_member_function_pointer
std::is_member_function_pointer 是一个模板类,用于检查一个类型是否为成员函数指针类型。
定义:
cpp
template< class T >
struct is_member_function_pointer;
当 T 为为成员函数指针类型则为 true,否则为 false。
样例:
cpp
#include <iostream>
#include <type_traits>
struct MyClass {
void myMemberFunction() {}
};
int main() {
std::cout << std::boolalpha;
std::cout << "Pointer to member function is "
<< std::is_member_function_pointer<void (MyClass::*)()>::value << '\n'; // 输出 true
std::cout << "Pointer to data member is "
<< std::is_member_function_pointer<int (MyClass::*)>::value << '\n'; // 输出 false
std::cout << "int is " << std::is_member_function_pointer<int>::value << '\n'; // 输出 false
return 0;
}
1.6 std::is_member_object_pointer
std::is_member_object_pointer 是一个模板类,用于检查一个类型是否为成员对象指针类型。
定义:
cpp
template< class T >
struct is_member_object_pointer;
当 T 为成员对象指针类型则为 true,否则为 false。
样例:
cpp
#include <iostream>
#include <type_traits>
struct MyClass {
int myMemberVariable;
};
int main() {
std::cout << std::boolalpha;
std::cout << "Pointer to member object is "
<< std::is_member_object_pointer<int (MyClass::*)>::value << '\n'; // 输出 true
std::cout << "Pointer to member function is "
<< std::is_member_object_pointer<void (MyClass::*)()>::value << '\n'; // 输出 false
std::cout << "int is " << std::is_member_object_pointer<int>::value << '\n'; // 输出 false
return 0;
}
2 type_traits 复合类型特性在模板元编程中的应用
以下是一个综合示例,它展示了如何在模板类和模板函数中根据类型是否为函数或类来定制行为。
cpp
#include <iostream>
#include <type_traits>
// 模板类,根据类型T是否为类来提供不同的成员
template<typename T>
class MyClass {
public:
void doSomething() {
if (std::is_class<T>::value) {
std::cout << "T is a class type." << std::endl;
// 执行针对类类型的操作
}
else {
std::cout << "T is not a class type." << std::endl;
// 执行针对非类类型的操作
}
}
};
// 模板函数,根据类型T是否为函数来执行不同的逻辑
template<typename T>
typename std::enable_if<!std::is_function<T>::value>::type
handleType() {
std::cout << "The type is not a function type." << std::endl;
// 执行针对非函数类型的操作
}
template<typename T>
typename std::enable_if<std::is_function<T>::value>::type
handleType() {
std::cout << "The type is a function type." << std::endl;
// 执行针对函数类型的操作
}
// 一个示例函数类型
void exampleFunction() {}
int main()
{
// 使用MyClass模板类,测试int类型和自定义结构体类型
MyClass<int> intInstance;
intInstance.doSomething(); // 输出: T is not a class type.
struct MyStructType {
// 自定义结构体
};
MyClass<MyStructType> structInstance;
structInstance.doSomething(); // 输出: T is a class type.
// 使用handleType模板函数,测试函数类型和int类型
handleType<decltype(exampleFunction)>(); // 输出: The type is a function type.
handleType<int>(); // 输出: The type is not a function type.
return 0;
}
上面代码的输出为:
T is not a class type.
T is a class type.
The type is a function type.
The type is not a function type.
在这个示例中,MyClass 模板类根据 T 是否为类类型来定制其 doSomething 方法的行为。如果 T 是类类型,它将输出相应的信息;否则,它将输出另一个信息。
handleType 模板函数使用了函数重载和 std::enable_if 来根据类型是否为函数类型来提供两个不同的模板函数实现。这是 SFINAE(Substitution Failure Is Not An Error)技术的一个应用,它允许编译器在模板解析阶段基于某个条件启用或禁用特定的函数模板。
3 type_traits 关系类型特性
3.1 std::is_base_of
std::is_base_of 是一个模板,用于检查一个类型是否是另一个类型的基类。
定义:
cpp
template<typename Base, typename Derived>
struct is_base_of;
这里 Base 表示基类,Derived 表示派生类。is_base_of 模板返回一个布尔类型的 std::integral_constant 实例,如果 Derived 公有继承自 Base,则返回 std::true_type,否则返回 std::false_type。
样例:
cpp
#include <iostream>
#include <type_traits>
class Base { };
class Derived : public Base { };
int main() {
// 检查 Derived 是否是 Base 的基类(应该返回 false)
bool is_base = std::is_base_of<Derived, Base>::value;
std::cout << std::boolalpha << "Is Derived a base of Base? " << is_base << std::endl; // 输出 false
// 检查 Base 是否是 Derived 的基类(应该返回 true)
bool is_derived = std::is_base_of<Base, Derived>::value;
std::cout << "Is Base a base of Derived? " << is_derived << std::endl; // 输出 true
return 0;
}
3.2 std::is_convertible
std::is_convertible 是一个模板,用于检查一个类型是否可以隐式转换为另一个类型。
定义:
cpp
template<typename From, typename To>
struct is_convertible;
这里 From 表示要转换的源类型,To 表示目标类型。is_convertible 模板返回一个布尔类型的 std::integral_constant 实例,如果 From 类型可以隐式转换为 To 类型,则返回 std::true_type,否则返回 std::false_type。
样例:
cpp
#include <iostream>
#include <type_traits>
int main() {
// 检查 int 是否可以转换为 double(应该返回 true)
bool is_convertible = std::is_convertible<int, double>::value;
std::cout << std::boolalpha << "Is int convertible to double? " << is_convertible << std::endl; // 输出 true
// 检查 const char* 是否可以转换为 std::string(应该返回 true,因为 const char* 可以隐式转换为 std::string)
bool is_string_convertible = std::is_convertible<const char*, std::string>::value;
std::cout << "Is const char* convertible to std::string? " << is_string_convertible << std::endl; // 输出 true
// 检查 std::string 是否可以转换为 int(应该返回 false)
bool is_int_convertible = std::is_convertible<std::string, int>::value;
std::cout << "Is std::string convertible to int? " << is_int_convertible << std::endl; // 输出 false
return 0;
}
4 type_traits 关系类型特性在工厂模式中的应用
下面是一个使用 std::is_base_of 应用于工厂模式的示例。这个示例将创建一个工厂类,它根据传入的类型参数创建不同的对象。然后使用 std::is_base_of 来确保请求创建的对象类型是从某个基类继承的。
首先,定义一个基类和一些派生类:
cpp
#include <iostream>
#include <string>
#include <type_traits>
#include <map>
#include <memory>
class Base {
public:
virtual ~Base() {}
virtual void print() const = 0;
};
class DerivedA : public Base {
public:
void print() const override { std::cout << "DerivedA\n"; }
};
class DerivedB : public Base {
public:
void print() const override { std::cout << "DerivedB\n"; }
};
接下来,实现一个工厂类,它使用 std::is_base_of 来确保请求的类型是从Base类继承的:
cpp
class Factory {
public:
template<typename T>
static void registerType(const std::string& name) {
creators[name] = &createT<T>;
}
template<typename T>
static std::enable_if_t<std::is_base_of<Base, T>::value, std::unique_ptr<Base>> create(const std::string& name) {
auto it = creators.find(name);
if (it != creators.end()) {
return std::unique_ptr<Base>(it->second());
}
throw std::invalid_argument("Unknown type name");
}
template<typename T>
static std::enable_if_t<!std::is_base_of<Base, T>::value, std::unique_ptr<Base>> create(const std::string& name) = delete;
private:
template<typename T>
static Base* createT() {
return new T();
}
private:
static std::map<std::string, Base*(*)()> creators;
};
std::map<std::string, Base*(*)()> Factory::creators;
template<typename T>
void registerType() {
static_assert(std::is_base_of<Base, T>::value, "Type must be derived from Base");
Factory::registerType<T>(typeid(T).name());
}
注意,这里使用 std::enable_if_t 和 SFINAE 来在编译时启用或禁用工厂类的 create 方法。同时也使用了一个静态断言来确保在注册类型时,类型是从 Base 类继承的。
现在,可以注册类型并使用工厂来创建对象:
cpp
int main()
{
// 注册类型
registerType<DerivedA>();
registerType<DerivedB>();
// 通过字符串创建对象
try {
auto objA = Factory::create<Base>("class DerivedA"); // 注意:这里使用了typeid(DerivedA).name()的结果,实际使用中应使用更稳定的类型名称映射
objA->print(); // 输出: DerivedA
auto objB = Factory::create<Base>("class DerivedB"); // 注意:这里使用了typeid(DerivedB).name()的结果,实际使用中应使用更稳定的类型名称映射
objB->print(); // 输出: DerivedB
}
catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
上面代码的输出为:
DerivedA
DerivedB
注意,上面的示例中使用了 typeid(T).name() 来获取类型的名称,这通常不是一个好的实践,因为 name() 返回的字符串格式是依赖于实现的,并且在不同的编译器或平台之间可能不同。在实际应用中,应该使用一种更稳定的方式来映射类型名称,比如使用枚举、字符串常量或者专门的类型注册机制。
此外,在这个例子中并没有用到 std::is_convertible ,因为这里的工厂是通过类型名称直接映射到创建函数的,而不是通过类型之间的转换。如果需要基于某种形式的类型标识(如字符串或整数)来间接地创建对象,并且这个标识可以转换为具体的类型,那么 std::is_convertible 可以用来检查这种转换是否合法。