Modern C++ 学习笔记(21)——模板元编程
首先,让我们通过一个简单的示例了解编译期阶乘计算。通过使用模板递归,我们可以设计一个模板函数,用于在编译期计算一个数的阶乘。基本情形为0的阶乘为1,通过递归调用自身来计算更大的数的阶乘。在运行时,可通过`::value`访问编译期计算的结果,这是静态常量值。
虽然在编译期计算阶乘并非必需使用模板元编程,但这种方法为递归模板的实现提供了优秀示例。与普通函数相比,通过将阶乘计算放入模板函数中,我们能够在编译阶段进行优化,减少运行时的计算开销。
接下来,我们探讨循环展开。模板元编程可用于在编译期循环展开,而非在运行时执行循环。通过使用模板递归,我们可以在每次递归中实例化自身,以达到循环展开的效果。当循环到达基本情形时(如循环计数为0),递归停止。这种实现方式在某些情况下能够优化性能,尤其是在循环体包含昂贵操作时。
打印元组是模板元编程的另一个应用。通过递归模板和辅助函数,我们可以实现打印std::tuple中元素的功能。使用模板元编程能够简洁地处理复杂的类型和结构,简化代码实现和维护。
引入constexpr if语句,C++17提供了在编译期执行if语句的能力,这进一步简化了模板元编程的实现。通过constexpr if,我们能够停止递归,简化代码结构,减少模板的复杂性。例如,在打印元组的实现中,我们不再需要模板递归的基本情形,因为constexpr if已经能够帮助我们实现相同的效果。
类型trait是模板元编程中的高级功能,用于在编译时根据类型做出决策。例如,我们可以通过类型trait验证类型是否派生自另一个类型、是否可以转换为另一个类型,甚至是否是整型等。这些特性使得类型trait成为编写灵活和强大的C++代码的关键工具。例如,`std::is_integral`可以用于验证类型是否为整型,从而在代码中做出相应的决策。
除了基础的类型trait,C++还提供了更高级的类型关系,如`std::is_same`、`std::is_base_of`和`std::is_convertible`,用于判断类型间的关系。这些功能使得模板元编程能够处理复杂的类型系统,提高代码的可读性和维护性。
在模板元编程中,`std::conditional`类型trait用于实现基于条件的类型选择,而`std::move_is_noexcept`等标准库辅助函数模板则用于根据类型特性选择不同的操作。这些功能使得C++的模板系统更加灵活和强大。
最后,`std::enable_if`是模板元编程中的一个关键特性,用于根据类型特性选择重载函数的实现。通过`std::enable_if`,我们可以基于类型特性有条件地启用特定的函数模板,从而实现灵活的代码结构和优化。
《Effective Modern C++》笔记
C++11中,rvalues和lvalues的概念在概念上(尽管在实践中并非总是如此)被定义为:rvalues通常对应于函数返回的临时对象,而lvalues则是可以被直接引用的对象,包括通过名字或指针。判断一个表达式是否为lvalue的一个简便方法是询问能否获取它的地址。使用auto类型时,它与模板类型推导有相似的规则,唯一的区...
Modern C++ 学习笔记(1)——基础语法
1.1 变量 - 变量声明有统一初始化语法和赋值语法两种方式。使用std::byte 类型表示单个字节,这在C++17之前由char 或 unsigned char 类型承担。std::byte 类型旨在明确表示内存中的单个字节,可以通过以下方式初始化。1.2 数值极限 - C++提供了通过std::numeric_limits类模板获取数值极限信息的标准方式。
Modern C++ 学习笔记(3)——format
在C++20之前,格式化字符串主要通过C风格的printf()函数或C++的I\/O流实现。然而,C++20引入了std::format()函数,旨在提供一种更安全、更可扩展的字符串格式化方式。该功能定义在中,集成了printf()和I\/O流的优点。使用std::format(),只需提供待格式化的字符串和用于填充占位符的值。通常,占位符...
Modern C++学习笔记:移动语义(1)
在C++11之前,引用主要类似于常量指针,分为T&和const T&。从C++11起,左值与右值的概念更为复杂,右值引用(T&&)可以绑定到右值上。右值引用的引入是为了实现移动语义,即在对象即将消亡时,直接转移资源,避免不必要的拷贝和释放,显著减少开销。在C++11中,值类别被重新定义,分为泛左值(glvalue)...
Modern C++ 学习笔记(19)——variant, any, tuple
现代C++中,variant, any, tuple是三种强大的类型系统,分别用于存储不同类型的数据或处理异构数据。variant允许在单一存储位置存储多种类型之一,any则提供了可包含任何类型值的能力,而tuple则用于存储固定数量且类型明确的元素。variant的使用需要预先指定可能的类型,如可以存储int、string或float。variant值...
Modern C++ 学习笔记(22)——多线程
线程管理还包括取消线程的能力。在某些情况下,可以通过传递`stop_token`给线程来实现这一功能,或者使用C++20引入的`jthread`类,它支持协作式取消机制。`jthread`类需要定期检查是否需要取消自身。从线程中获取结果通常涉及使用`future`对象来处理线程中可能发生的错误。此外,C++标准库提供了一系列原子操作...
Modern C++ 学习笔记(20)——高级模板
现代C++学习笔记(20)深入探讨高级模板,包括类型参数、非类型参数和template template参数。1. 类型参数:可声明任意数量,如给Grid类添加一个表示底层容器类型的参数,如vector或deque。实例化时需要指定完整参数,如Grid。2. template template参数:用于接收容器模板作为参数,如Grid,允许接收vector或deque...
Modern C++ 学习笔记(4)——初始化
初始化是现代C++学习中的关键概念,它在构造时为变量提供初始值。初始化器可以由声明符或new表达式的初始化器部分提供,同样,函数调用时也会发生初始化,如函数形参及函数返回值。如果未提供初始化器,会应用默认初始化规则。初始化涉及对初始化器中的子表达式求值,以及为函数实参和返回值创建临时对象。...
如何评价modernc++design(c++设计新思维)这本书?
本书《Modern C++ Design: Generic Programming and Design Patterns Applied》以全新的视角审视C++,引领读者探索现代C++设计的新思维。初读时,可能因其深度与复杂性感到困惑,但随着理解的加深,读者会发现其中蕴含的宝贵价值。对于初学者而言,本书可能显得难以理解,但通过持续学习和实践,能够逐渐掌握C++...
Modern C++ 学习笔记(20)——高级模板
现代C++学习深入探讨了模板的高级特性,包括类型参数、非类型参数和template template参数。首先,类型参数允许用户自定义Grid类的模板,例如,使用deque替换vector,但需要满足特定的Container概念。默认情况下,Grid使用vector,如Grid。模板参数的默认值使得代码更加简洁,如Grid<T, vector> Grid;。然而,当...