突破编程_C++_C++11新特性(type_traits的复合类型特性以及关系类型特性)

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 可以用来检查这种转换是否合法。

相关推荐
霁月风9 分钟前
设计模式——适配器模式
c++·适配器模式
sp_fyf_202410 分钟前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
萧鼎20 分钟前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸21 分钟前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农21 分钟前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^22 分钟前
数据库连接池的创建
java·开发语言·数据库
秋の花30 分钟前
【JAVA基础】Java集合基础
java·开发语言·windows
香菜大丸31 分钟前
链表的归并排序
数据结构·算法·链表
jrrz082831 分钟前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
小松学前端33 分钟前
第六章 7.0 LinkList
java·开发语言·网络