鹰潭律师网站建设,网站开发 net,wordpress去除谷歌字体,wordpress模板修改内容目录 C 元编程1. 术语2. 元函数1. 数值元函数示例#xff1a;阶乘计算 2. 类型元函数示例#xff1a;类型选择 3. 混合编程1. 常规的计算点积范例2. 混合元编程计算点积 4. typelist实现设计和基本操作接口#xff08;算法#xff09;完整代码 5. tuple 实现基础知识1. 左值… 目录 C 元编程1. 术语2. 元函数1. 数值元函数示例阶乘计算 2. 类型元函数示例类型选择 3. 混合编程1. 常规的计算点积范例2. 混合元编程计算点积 4. typelist实现设计和基本操作接口算法完整代码 5. tuple 实现基础知识1. 左值、右值、左值引用、右值引用2. std::move 究竟做了什么3. std::forward 究竟做了什么4. 万能引用转发引用5. 完美转发 tuple 实现示例 C 元编程 元编程的主要目的在于将各种计算从运行期提前至编译期进行以实现程序运行时的性能提升。也正因如此元编程是一种增加程序的编译时间从而提升程序运行效率的编程技术。 在元编程中涉及许多与循环相关的代码。传统编程中循环通常采用 for、while 等语句实现这些语句一般针对的是运行期的条件变量而在元编程中更多的操作其实是针对类型或常量的。这种循环的实现往往会采用递归的手段使得编译器能够在编译期间完成某些计算。
1. 术语 元编程的英文名称是 Meta Programming有时也称为 模板元编程Template Metaprogramming。可以理解为一种编程手法用于实现一些比较特殊的功能。元编程与“递归”这一概念紧密相连代表着在元编程中大多数情况下都会使用递归编程技术。 模板编程主要应用在泛型编程和元编程
泛型编程Generic Programming强调的是“通用”的概念旨在通过抽象和参数化来实现代码的复用与灵活性。在泛型编程中程序员可以编写与类型无关的算法和数据结构使得同一段代码能够适用于多种类型。模板的设计初衷正是为了满足这一需求。
元编程Meta Programming则是一种更高级的编程技巧旨在通过编译期间的计算和推导来实现某些功能。元编程允许程序员在编译期进行复杂的逻辑处理通常这些逻辑在运行时才能完成。
2. 元函数 传统的函数都是在程序运行期间被调用和执行的函数而元函数是能在程序编译期间被调用和执行的函数编译期间就能得到结果。引入元函数概念的目的是支持元编程而元编程的核心也正是元函数。 1. 数值元函数 数值元函数是在编译期间对数值进行计算的元函数。这类元函数可以接收整型常量作为模板参数并根据这些常量进行编译时计算。数值元函数通常用于实现一些数学运算如阶乘、斐波那契数列等。 示例阶乘计算
templateint N
struct Factorial {static const int value N * FactorialN - 1::value;
};template
struct Factorial0 {static const int value 1;
};// 使用
constexpr int fact5 Factorial5::value; // fact5 的值为 120
std::cout fact5 std::endl; // 输出 1202. 类型元函数 类型元函数则是针对类型进行操作的元函数。它们允许程序员在编译期间对类型进行推导、选择和变换。这类元函数非常适合于类型特征提取和类型转换等场景。 示例类型选择
templatebool Condition, typename TrueType, typename FalseType
struct Conditional;templatetypename TrueType, typename FalseType
struct Conditionaltrue, TrueType, FalseType {using type TrueType;
};templatetypename TrueType, typename FalseType
struct Conditionalfalse, TrueType, FalseType {using type FalseType;
};// 使用
using ResultType Conditionaltrue, int, double::type; // ResultType 的类型为 int3. 混合编程 混合编程是结合了运行时和编译时计算的技术允许程序员在编译期间进行一些运算同时时间复杂度也得到优化。混合编程的关键在于利用模板和递归来处理类型和数值使得某些操作可以在编译期完成从而提高运行时性能。 1. 常规的计算点积范例
混合元编程方面一个比较典型的案例是计算两个向量数组点积。
1数组a有3个元素a[0]、a[1]、a[2]值分别为1、2、3
2数组b有3个元素b[0]、b[1]、b[2]值分别为4、5、6
3a和b的点积是一个数值结果为a[0]×b[0] a[1] ×b[1] a[2] ×b[2] 1×42×53×632。
在传统编程中计算两个数组向量的点积通常使用循环结构如for或while。以下是一个简单的点积计算示例
#include iostreamtemplatetypename T, int U
auto DotProduct(T* array1, T* array2)
{T dpresult T{};for (int i 0; i U; i){dpresult array1[i] * array2[i];}return dpresult;
}int main()
{int a[] { 1,2,3 };int b[] { 4,5,6 };int result DotProductint, 3(a, b);std::cout result std::endl; // 输出 32return 0;
}2. 混合元编程计算点积
通过元编程可以在编译期间计算点积。下面的代码展示了如何使用模板和递归实现这一点
#include iostream//泛化版本
templatetypename T, int U //T元素类型U数组大小
struct DotProduct
{static T result(const T* a, const T* b){return (*a) * (*b) DotProductT, U - 1::result(a 1, b 1);}
};
//特化版本作为递归调用的出口
templatetypename T
struct DotProductT, 0
{static T result(const T *,const T*){return T{};}
};int main()
{int a[] { 1,2,3 };int b[] { 4,5,6 };int result DotProductint, 3::result(a, b);std::cout result std::endl;return 0;
}泛化版本: DotProduct 是一个模板类它接受元素类型 T 和数组大小 U 作为模板参数。result 函数是一个静态成员函数通过递归调用来计算点积。它取当前元素 *a 和 *b 的乘积并加上对下一个元素的递归调用。 特化版本: 当 U 为 0 时递归调用的出口到达。此时返回一个默认初始化的值 T{}表示点积计算的结束。
4. typelist实现
typelist的解释为用来操作一大堆类型的C容器就像C标准库中的list容器能够为数值提供各种基本操作一样只不过这里操作的不是数值而是类型。
从实现上来讲typelist是一个类模板译为“类型列表”这个类模板用来表示一个列表这个列表中存放着一堆类型。
设计和基本操作接口算法
Typelist 的基本定义
templatetypename... Types
struct TypeList {};// 基本类型操作
using EmptyTypeList TypeList; // 空类型列表1. 取得typelist中的第1个元素front
这个操作返回 typelist 中的第一个类型。通过模板特化可以在编译时获取到这个类型。该操作通常用于获取类型链的起始类型以便后续处理。
templatetypename TList
struct Front;templatetypename Head, typename... Tail
struct FrontTypeListHead, Tail... {using type Head; // 返回第一个元素
};2. 取得typelist容器中元素的数量size
这个操作计算并返回 typelist 中包含的类型数量。它使用可变参数模板的特性通过 sizeof... 来计算类型的数量。
templatetypename TList
struct Size;templatetypename... Types
struct SizeTypeListTypes... {static const size_t value sizeof...(Types); // 元素计数
};3. 从typelist中移除第1个元素pop_front
此操作会返回一个新的 typelist该列表中不再包含第一个类型。它通过递归去掉开头的类型为后续操作提供了简化的列表。
templatetypename TList
struct PopFront;templatetypename Head, typename... Tail
struct PopFrontTypeListHead, Tail... {using type TypeListTail...; // 移除第一个元素
};4. 向typelist的开头和结尾插入一个元素push_front和push_back
push_front: 将新类型插入到 typelist 的开头产生一个新的 typelist。push_back: 将新类型插入到 typelist 的结尾同样产生一个新的 typelist。
templatetypename TList, typename NewType
struct PushFront;templatetypename... Types, typename NewType
struct PushFrontTypeListTypes..., NewType {using type TypeListNewType, Types...; // 插入到开头
};templatetypename TList, typename NewType
struct PushBack;templatetypename... Types, typename NewType
struct PushBackTypeListTypes..., NewType {using type TypeListTypes..., NewType; // 插入到结尾
};5. 替换typelist的开头元素replace_front
此操作允许替换 typelist 的第一个类型为一个新的类型并返回一个新的 typelist。这对于动态更改类型列表的开头非常有用。
templatetypename TList, typename NewType
struct ReplaceFront;templatetypename... Tail, typename NewType
struct ReplaceFrontTypeListTail..., NewType {using type TypeListNewType, Tail...; // 替换开头元素
};6. 判断typelist是否为空is_empty
此操作检查 typelist 是否包含任何类型。如果列表为空返回 true否则返回 false。这是确保操作安全性的重要步骤。
templatetypename TList
struct IsEmpty;template
struct IsEmptyEmptyTypeList {static const bool value true; // 空类型列表
};templatetypename... Types
struct IsEmptyTypeListTypes... {static const bool value false; // 非空类型列表
};7. 根据索引号查找typelist的某个元素find
此操作通过索引查找 typelist 中的特定类型。它使用递归进行索引减小直到找到目标索引的类型。这使得可以根据位置快速访问特定类型。
templatetypename TList, size_t Index
struct Find;templatetypename Head, typename... Tail
struct FindTypeListHead, Tail..., 0 {using type Head; // 找到第一个元素
};templatetypename Head, typename... Tail, size_t Index
struct FindTypeListHead, Tail..., Index {using type typename FindTypeListTail..., Index - 1::type; // 递归查找下一个元素
};8. 遍历typelist找到sizeof值最大的元素get_maxsize_type
该操作遍历 typelist 中的所有类型并返回 sizeof 值最大的类型。它利用条件选择递归比较每个类型的大小确定最大值。这在需要根据类型大小进行处理时非常有用。
templatetypename TList
struct GetMaxSizeType;templatetypename Head, typename... Tail
struct GetMaxSizeTypeTypeListHead, Tail... {using type typename std::conditional(sizeof(Head) sizeof(typename GetMaxSizeTypeTypeListTail...::type)),Head,typename GetMaxSizeTypeTypeListTail...::type::type; // 使用 std::conditional 比较
};// 特化版本处理空类型列表
template
struct GetMaxSizeTypeEmptyTypeList {using type void; // 空类型列表没有最大类型
};完整代码
#include iostream
#include type_traitstemplatetypename... Types
struct TypeList {};using EmptyTypeList TypeList;// 取得第一个元素
templatetypename TList
struct Front;templatetypename Head, typename... Tail
struct FrontTypeListHead, Tail... {using type Head;
};// 取得元素数量
templatetypename TList
struct Size;templatetypename... Types
struct SizeTypeListTypes... {static const size_t value sizeof...(Types);
};// 移除第一个元素
templatetypename TList
struct PopFront;templatetypename Head, typename... Tail
struct PopFrontTypeListHead, Tail... {using type TypeListTail...;
};// 向开头插入一个元素
templatetypename TList, typename NewType
struct PushFront;templatetypename... Types, typename NewType
struct PushFrontTypeListTypes..., NewType {using type TypeListNewType, Types...;
};// 向结尾插入一个元素
templatetypename TList, typename NewType
struct PushBack;templatetypename... Types, typename NewType
struct PushBackTypeListTypes..., NewType {using type TypeListTypes..., NewType;
};// 替换开头元素
templatetypename TList, typename NewType
struct ReplaceFront;templatetypename... Tail, typename NewType
struct ReplaceFrontTypeListTail..., NewType {using type TypeListNewType, Tail...;
};// 判断是否为空
templatetypename TList
struct IsEmpty;template
struct IsEmptyEmptyTypeList {static const bool value true;
};templatetypename... Types
struct IsEmptyTypeListTypes... {static const bool value false;
};// 根据索引查找元素
templatetypename TList, size_t Index
struct Find;templatetypename Head, typename... Tail
struct FindTypeListHead, Tail..., 0 {using type Head; // 找到第一个元素
};templatetypename Head, typename... Tail, size_t Index
struct FindTypeListHead, Tail..., Index {using type typename FindTypeListTail..., Index - 1::type; // 递归查找下一个元素
};// 遍历找到最大 sizeof 的类型
templatetypename TList
struct GetMaxSizeType;templatetypename Head, typename... Tail
struct GetMaxSizeTypeTypeListHead, Tail... {using type typename std::conditional(sizeof(Head) sizeof(typename GetMaxSizeTypeTypeListTail...::type)),Head,typename GetMaxSizeTypeTypeListTail...::type::type; // 使用 std::conditional 比较
};// 特化版本处理空类型列表
template
struct GetMaxSizeTypeEmptyTypeList {using type void; // 空类型列表没有最大类型
};// 测试
int main() {using MyTypes TypeListint, double, char;std::cout Size: SizeMyTypes::value std::endl; // 输出 3std::cout Is empty: IsEmptyMyTypes::value std::endl; // 输出 0std::cout First element type: typeid(FrontMyTypes::type).name() std::endl; // 输出 intusing Popped typename PopFrontMyTypes::type;std::cout Size after pop: SizePopped::value std::endl; // 输出 2using PushedFront typename PushFrontMyTypes, float::type;std::cout Size after push front: SizePushedFront::value std::endl; // 输出 4using PushedBack typename PushBackMyTypes, long::type;std::cout Size after push back: SizePushedBack::value std::endl; // 输出 4using FoundType typename FindMyTypes, 1::type; // 查找索引1的类型std::cout Found type at index 1: typeid(FoundType).name() std::endl; // 输出 doubleusing MaxSizeType typename GetMaxSizeTypeMyTypes::type; // 查找最大 sizeof 的类型std::cout Max size type: typeid(MaxSizeType).name() std::endl; // 输出 doublereturn 0;
}TypeList: 用于存储类型的模板类。基本操作: 提供了如获取第一个元素、计算大小、移除元素、插入元素、替换元素和判断是否为空等基本操作。Find: 通过递归查找指定索引的类型。GetMaxSizeType: 通过比较各类型的 sizeof 值找出最大类型。使用示例: 在 main 函数中演示了如何使用这些操作。
5. tuple 实现
基础知识
1. 左值、右值、左值引用、右值引用 左值和右值: 左值 (lvalue): 表示一个可以被取地址的对象具有持久的内存位置。例子int i 10; 这里的 i 是左值。右值 (rvalue): 表示一个临时的对象通常是不能取地址的存在于表达式的右边。例子10 是右值。 左值引用: 通过左值引用 () 可以引用一个左值。例子int j i; // j 是左值引用左值引用只能绑定到左值上。尝试将右值绑定到左值引用会导致编译错误但 const 左值引用可以绑定到右值const int j 10; // 合法右值引用: 右值引用使用 进行声明允许绑定到右值。例如int k 10; // k 是右值引用右值引用只能绑定到右值。尝试将左值绑定到右值引用会导致编译错误。 普通变量: 普通的变量如 int m;既不是左值引用也不是右值引用因为引用必须带有 或 修饰符。
2. std::move 究竟做了什么 std::move 是一个标准库函数它将左值转换为右值从而允许使用右值引用。例如 int k std::move(i); // 将左值 i 转换为右值重要的是std::move 不会执行任何移动操作它只是一种类型转换标记一个对象可以被“移动”。
3. std::forward 究竟做了什么 std::forward 是用于实现完美转发的工具它允许保持参数的值类别lvalue 或 rvalue。在模板中使用时可以根据传入的参数类型决定是保持为左值还是右值。 templatetypename T
void func(T arg) {// 完美转发process(std::forwardT(arg));
}4. 万能引用转发引用
万能引用是指在模板参数中使用的引用类型可以绑定到左值或右值例如 T其中 T 是模板参数。这种引用在模板中被称为转发引用。
5. 完美转发
完美转发使得函数可以根据实际传入的参数类型选择合适的引用类型从而避免不必要的复制和保证性能。例如结合 std::forward 和万能引用可以实现完美转发。
tuple 实现示例
C 标准库中的 std::tuple 是一个可以存储不同类型的元素的容器以下是一个简单的自定义 tuple 实现示例
tuple 是一种灵活的数据结构能够存储不同类型的元素。理解左值、右值及其引用非常重要因为 tuple 的实现涉及到对象的生命周期管理、内存效率以及函数调用方式如移动语义和转发。std::move 和 std::forward 是实现高效代码的重要工具特别是在模板编程和泛型编程中。
#include iostream
#include utility
#include type_traitstemplatetypename... Types
class MyTuple;// 特化基础情况
template
class MyTuple {};// 递归定义
templatetypename Head, typename... Tail
class MyTupleHead, Tail... : private MyTupleTail... {
public:Head head; // 当前元素using MyTupleTail...::head; // 继承下一层的头部元素MyTuple(Head h, Tail... t): head(h), MyTupleTail...(t...) {} // 构造函数
};// 获取元素
templatesize_t Index, typename Tuple
struct TupleElement;templatetypename Head, typename... Tail
struct TupleElement0, MyTupleHead, Tail... {using type Head; // 返回当前头部元素
};templatesize_t Index, typename Head, typename... Tail
struct TupleElementIndex, MyTupleHead, Tail... {using type typename TupleElementIndex - 1, MyTupleTail...::type; // 递归获取
};// 获取元素的辅助函数
templatesize_t Index, typename... Types
typename TupleElementIndex, MyTupleTypes...::type get(MyTupleTypes... tuple) {return static_casttypename TupleElementIndex, MyTupleTypes...::type(tuple);
}int main() {MyTupleint, double, char myTuple(1, 2.5, c);std::cout First element: get0(myTuple) std::endl; // 输出 1std::cout Second element: get1(myTuple) std::endl; // 输出 2.5std::cout Third element: get2(myTuple) std::endl; // 输出 creturn 0;
}