D语言中的模板

D语言游戏编程(11):D语言基础之模板和混入(mixin)技术     D语言通过模板,很好的支持泛型编程。与C++的模板相比较,各有优略。总体上说,D语言的模板在很多方面还是很方便的。     D语言还支持模板的混入(mixin),简单的讲就是把模板实例化之后,将模板中的代码插入到当前的位置。这是一个非常方便的工具!    具体的,请看下面的演示代码。import std.stdio;void main()...{    tryTemplate(); 阅读详情

模板

D通过模板实现泛型编程。模板声明 定义为:
	模板声明:
		template 模板标志符 ( 模板参数列表 )
			{ 声明定义 }

	模板标志符:
		标志符

	模板参数列表
		模板参数
		模板参数 , 模板参数列表

	模板参数:
		类型参数
		值参数
		别名参数

	模板类型参数:
		标志符
		标志符 模板类型参数特化
		标志符 模板类型参数默认值
		标志符 模板类型参数特化 模板类型参数默认值

	模板类型参数特化:
		 : 类型

	模板类型参数默认值:
		 = 类型

	模板值参数:
		声明
		声明 模板值参数特化
		声明 模板值参数默认值
		声明 模板值参数特化 模板值参数默认值

	模板值参数特化:
		 : 条件表达式

	模板值参数默认值:
		 = 条件表达式

	模板别名参数:
		alias 标志符
		alias 标志符 模板别名参数默认值

	模板别名参数默认值:
		 = 类型
	TemplateDeclaration:
		template TemplateIdentifier ( TemplateParameterList )
			{ DeclDefs }

	TemplateIdentifier:
		Identifier

	TemplateParameterList
		TemplateParameter
		TemplateParameter , TemplateParameterList

	TemplateParameter:
		TypeParameter
		ValueParameter
		AliasParameter

	TemplateTypeParameter:
		Identifier
		Identifier TemplateTypeParameterSpecialization
		Identifier TemplateTypeParameterDefault
		Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault

	TemplateTypeParameterSpecialization:
		 : Type

	TemplateTypeParameterDefault:
		 = Type

	TemplateValueParameter:
		Declaration
		Declaration TemplateValueParameterSpecialization
		Declaration TemplateValueParameterDefault
		Declaration TemplateValueParameterSpecialization TemplateValueParameterDefault

	TemplateValueParameterSpecialization:
		 : ConditionalExpression

	TemplateValueParameterDefault:
		 = ConditionalExpression

	TemplateAliasParameter:
		alias Identifier
		alias Identifier TemplateAliasParameterDefault

	TemplateAliasParameterDefault:
		 = Type
	
无论模板是否被最终实例化,模板声明 的过程体在语法上必须是正确的。语义分析延迟到模板实例化时进行。模板有自己的作用域,模板过程体中可以包括类、结构、类型、枚举、变量、函数或者其它模板。

模板参数可以是类型、值或者符号。可以使用任何类型。值参数必须是整数型,在特化时它们必须被解析为整数常量。符号可以是任何非局部符号。

模板参数特化将值或类型约束为 模板参数 可以接受的值或类型。

模板参数默认值用在不提供 模板参数 时。

模板实例化

模板的实例体定义为:
	模板实例:
		模板标志符 !( 模板参数列表 )

	模板参数列表:
		模板参数
		模板参数 , 模板参数列表

	模板参数:
		类型
		赋值表达式
		符号
	TemplateInstance:
		TemplateIdentifer !( TemplateArgumentList )

	TemplateArgumentList:
		TemplateArgument
		TemplateArgument , TemplateArgumentList

	TemplateArgument:
		Type
		AssignExpression
		Symbol
一旦被实例化,位于模板内的声明,称做模板成员,就位于 TemplateInstance 作用域内:
	template TFoo(T) { alias T* t; }
	...
	TFoo!(int).t x;		// 声明 x 为 int* 类型
	
模板实例化可以有别名:
	template TFoo(T) { alias T* t; }
	alias TFoo!(int) abc;
	abc.t x;			// 声明 x 为 int* 类型
	
一个 模板声明 拥有相同 模板参数列表 的多个实例将引用相同的实例。例如:
	template TFoo(T) { T f; }
	alias TFoo(int) a;
	alias TFoo(int) b;
	...
	a.f = 3;
	assert(b.f == 3);		// a 和 b 引用相同的 TFoo 实例
	
即使 模板实例 位于不同的模块中,这条规则也成立。

如果声明了拥有多个相同 模板标志符 的模板,并且它们参数个数不同或者采用不同的特化,那么它们不同。

例如,一个简单的泛型复制函数可以是这个样子:

	template TCopy(T)
	{
	    void copy(out T to, T from)
	    {
		to = from;
	    }
	}
	
在使用模板之前,必须先使用具体的类型将其实例化:
	int i;
	TCopy!(int).copy(i, 3);
	

实例化作用域

模板实例 总是在声明 模板声明 的作用域内执行,另外声明的模板参数被看作它们所推出的类型的别名。

例如:

	-------- module a ---------
	template TFoo(T) { void bar() { func(); } }

	-------- module b ---------
	import a;

	void func() { }
	alias TFoo!(int) f;	// 错误:func 没有在模块 a 内定义
	
以及:
	-------- module a ---------
	template TFoo(T) { void bar() { func(1); } }
	void func(double d) { }

	-------- module b ---------
	import a;

	void func(int i) { }
	alias TFoo!(int) f;
	...
	f.bar();			// 将调用 a.func(double)
	
模板参数 的特化和默认值将在 模板声明 的作用域内估值。

参数推导

采用比较对应的模板参数(template parameter)和模板实参(template argument)的方法,模板实例中的模板参数的类型被推倒出来。

对于每个模板参数,按照下面的顺序逐条应用规则直到每个参数的类型都被推倒出来:

  1. 如果参数没有指定一个特化,参数的类型被设为指定的模板实参。
  2. 如果类型特化依赖于一个类型参数,这个参数的类型就被设为与那个类型实参对应的类型。
  3. 如果在检查了所有类型实参之后还有类型参数没有被分配类型,它们就会被分配给在 模板参数列表 中位于相同位置的模板实参。
  4. 如果应用上述规则之后,还不能做到每个模板参数都精确的对应唯一一个类型,那么就被视为错误。
例如:
	template TFoo(T) { }
	alias TFoo!(int) Foo1;		// (1) T 被推导为 int
	alias TFoo!(char*) Foo2;		// (1) T 被推导为 char*

	template TFoo(T : T*) { }
	alias TFoo!(char*) Foo3;		// (2) T 被推导为 char

	template TBar(D, U : D[]) { }
	alias TBar!(int, int[]) Bar1;	// (2) D 被推导为 int, U 被推导为 int[]
	alias TBar!(char, int[]) Bar2;	// (4) 错误,D 既是 char 又是 int

	template TBar(D : E*, E) { }
	alias TBar!(int*, int) Bar3;	// (1) E 是 int
					// (3) D 是 int*
	
当考虑匹配时,一个类被认为可以匹配任何父类或接口:
	class A { }
	class B : A { }

	template TFoo(T : A) { }
	alias TFoo!(B) Foo4;		// (3) T 是 B

	template TBar(T : U*, U : A) { }
	alias TBar!(B*, B) Foo5;		// (2) T 是 B*
					// (3) U 是 B
	

值参数

这个模板例子中,指定了一个为 10 的值参数:
	template foo(U : int, int T : 10)
	{
	    U x = T;
	}

	void main()
	{
	    assert(foo!(int, 10).x == 10);
	}
	

特化

模板可以通过在模板参数之后指定一个“:”和一个特化类型来将模板特化为使用某些指定的实参类型。例如:
	template TFoo(T)        { ... } 	// #1
	template TFoo(T : T[])  { ... } 	// #2
	template TFoo(T : char) { ... } 	// #3
	template TFoo(T,U,V)    { ... } 	// #4

	alias TFoo!(int) foo1;	       	// 实例化 #1
	alias TFoo!(double[]) foo2;    	// 实例化 #2 ,其中 T 为 double
	alias TFoo!(char) foo3;        	// 实例化 #3
	alias TFoo!(char, int) fooe;   	// 错误,实参个数不匹配
	alias TFoo!(char, int, int) foo4; 	// 实例化 #4
	
当进行模板实例化时,会挑选匹配 模板参数列表 的特化度最高的模板。决定那个模板更为特化的方式同 C++ 处理偏序规则的方式相同。如果结果是模棱两可的,就是错误。

别名参数

别名参数使模板能够使用任何 D 符号参数化,包括全局名称、类型名称、模板名称以及模板实例名称。局部名字可能不能作为别名参数。这是 C++ 中将模板作为模板参数的做法的超集。
  • 全局名
    	int x;
    
    	template Foo(alias X)
    	{
    	    static int* p = &X;
    	}
    
    	void test()
    	{
    	    alias Foo!(x) bar;
    	    *bar.p = 3;		// 设置 x 为 3
    	    int y;
    	    alias Foo!(y) abc; 	// 错误,y 是一个局部名称
    	}
  • 类型名
    	class Foo
    	{
    	    static int p;
    	}
    
    	template Bar(alias T)
    	{
    	    alias T.p q;
    	}
    
    	void test()
    	{
    	    alias Bar!(Foo) bar;
    	    bar.q = 3;		// 将 Foo.p 设置为 3
    	}
  • 模块名
    	import std.string;
    
    	template Foo(alias X)
    	{
    		alias X.toString y;
    	}
    
    	void test()
    	{
    	    alias Foo!(std.string) bar;
    	    bar.y(3);		// 调用 std.string.toString(3)
    	}
  • 模板名
    	int x;
    
    	template Foo(alias X)
    	{
    	    static int* p = &X;
    	}
    
    	template Bar(alias T)
    	{
    	    alias T!(x) abc;
    	}
    
    	void test()
    	{
    	    alias Bar!(Foo) bar;
    	    *bar.abc.p = 3;	// 设置 x 为 3
    	}
  • 模板别名
    	int x;
    
    	template Foo(alias X)
    	{
    	    static int* p = &X;
    	}
    
    	template Bar(alias T)
    	{
    	    alias T.p q;
    	}
    
    	void test()
    	{
    	    alias Foo!(x) foo;
    	    alias Bar!(foo) bar;
    	    *bar.q = 3;		// 设置 x 为 3
    	}

模板参数默认值

右端的模板参数(从最右端的那个开始向左连续的带有默认值的那些参数)可以有默认值:
	template Foo(T, U = int) { ... }
	Foo!(uint,long); 		// 实例化:T 为 uint ,U 为 long
	Foo!(uint);	 	// 实例化:T 为 uint ,U 为 int

	template Foo(T, U = T*) { ... }
	Foo!(uint);	 	// 实例化:T 为 uint ,U 为 uint*
	

隐式模板属性

如果模板有且只有一个成员,并且这个成员和模板同名的话,这个成员就被认为引用的是一个模板实例:
	template Foo(T)
	{
	    T Foo;		// 声明变量 Foo 为类型 T
	}

	void test()
	{
	    Foo!(int) = 6;	// 代替 Foo!(int).Foo
	}
	

类模板

	类模板声明:
		class 标志符( 模板参数列表) [父类{, 接口类}] 类过程体
	
	ClassTemplateDeclaration:
		class Identifier ( TemplateParameterList ) [SuperClass {, InterfaceClass }] ClassBody
	
如果一个模板声明且仅声明了一个成员,并且那个成员是一个同模板同名的类:
	template Bar(T)
	{
	    class Bar
	    {
		T member;
	    }
	}
	
则同下面的声明语义等价,称作 类模板声明 :
	class Bar(T)
	{
	    T member;
	}
	

递归模板

可以组合模板的各种特性来产生一些有趣的效果,例如在编译时对非平凡函数求值。例如,可以写一个计算阶乘的模板:
	template factorial(int n : 1)
	{
	    enum { factorial = 1 }
	}

	template factorial(int n)
	{
	    // 注意:‘.’用来在全局作用域而不是枚举作用域中查找模板
	    enum { factorial = n* .factorial!(n-1) }
	}

	void test()
	{
	    printf("%d/n", factorial!(4));	// 打印 24
	}
	

限制

模板不能用来给类添加非静态成员或函数。例如:
	class Foo
	{
	    template TBar(T)
	    {
		T xx;				// 错误
		int func(T) { ... }		// 错误

		static T yy;			// Ok
		static int func(T t, int y) { ... } 	// Ok
	    }
	}
	
不能在函数内部声明模板。
49、D语言模板高级特性详解 本博文深入讲解了D语言中模板的高级特性,包括元组模板参数、特殊的typeof变体、模板特化、元编程、编译时多态性等。同时讨论了模板使用中可能面临的挑战,如代码膨胀和参数兼容性问题,并提供了相应的解决策略。通过学习本博文,开发者可以掌握如何高效使用D语言模板,提升代码灵活性和性能。 阅读详情

相关推荐

D程序设计语言 (高清完整版) 适合初学者

《D程序设计语言》据说最容易学习理解的语言 不仅适合于D语言初学者,对于想学习编译器实现的研究人员、想拓展学生的编程语言知识面的教师以及想深入了解编程语言设计的人,也能提供很好的帮助和指导。

模 板 2.014

我想我可以担保地说没什么人理解了模板机制。 -- Richard Deyman [color=red]模板(Templates)是 D 实现泛型编程(generic programming)的方法[/color]。模板通过 模板声明 进行定义: 模板声明: template 模板标识符 ( 模板参数列表 ) { 多个声明定义 } 模板标识符: 标识符 模板参数列表 模板...

hqs7636的专栏 172

01_MySQL下载、安装与配置(以MySQL8.0.31版本为例)

1.点击下载好的mysql安装包 进入到mysql installer界面。2.选择MySQL Servers选项 一直下拉。

4820

从D语言看C++ Template语法

从D语言看C++ Template语法许式伟 (版权声明)2007-5-2D语言是一门新兴的语言,它试图结合C/C++性能上的高效,同时又象Python、Ruby等“现代”语言那样具备高效的生产力。优快云曾经对其做过专题报道。我本人蛮喜欢D语言的语法,觉得当之无愧的简洁典雅。当然需要澄清的是,我不想让人误会,我不是要倡导“C/C++已死,请使用D语言”。本文也没有打算全面去讨论D语言

QBox/Golang/CERL/StdExt/TPL/WinxGui - 许式伟的专栏 1万+

脑机接口技术介绍、应用与挑战

脑机接口的概念最先于1973年提出,伴随着计算机性能的飞速提高,在美国“人类脑计划”的资金支持下,脑机接口的研究进入了高速发展期。去年年末,我国科技部会议透露:中国将拿出540亿元,推进中国脑计划的发展。同时,这一举措也推动了我国脑机接口的研究发展。 脑机接口属于多学科交叉科技,涉及神经科学、计算机科学、认知科学、控制与信息科学技术、医学等多个学科。技术实现方式是通过信号采集设备从大脑皮层采集脑电信号,经过放大、滤波、A/D转换等处理,转换为可以被计算机识别的信号,然后对信号进行预处理,提取特征信号,再利

weixin_44603934的博客 9132

【计算机视觉】基于复杂环境下的车牌识别

本文针对复杂环境下(光照变化、车牌变形、噪声干扰)的车牌识别问题,提出了一套完整的优化方案。通过四个核心环节进行改进:1)采用CLAHE、同态滤波等技术优化光照处理;2)使用边缘检测和透视变换应对车牌变形;3)结合中值滤波和暗通道去噪算法消除干扰;4)改进字符分割与识别方法。文章提供了详细的Python实现代码,展示了从预处理到字符识别的完整流程,并通过多策略融合显著提升了复杂场景下的识别准确率。实验结果表明,该方法能有效应对各类复杂环境挑战,为实际应用提供了可靠解决方案。

2401_84149564的博客 1628

D语言的成员函数模板

DMD 0.166 特性列表中有一条: * ncorporated Oskar Linde's patches to support member templates. 当时没注意,今天看到邮件列表中的一个[url=http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalm...

头脑歪歪 201

使用buildroot系统的qmake编译QT出现Unknown module(s) in QT: xxxx 的错误解决方法

可以看到,我这里使用的是 qt5base-5.15.2 目录下的qmake,这个qmake只包含了基础的qt模块,而额外添加的qt模块没有包含进去,需要使用。可以看到我这里是有的,如果你跟我一样,模块存在,但是还是报找不到对应模块的错误的话,大概率是跟我一样,用错qmake了,看第二点。在包含 qt5base 目录下查看,是否有对应模块的目录,如果没有的话,需要通过make menuconfig 添加一下。目录下的qmake才可以。

T541132的博客 2490

D语言的模板

D语言的模板使用非常方便灵活,受够了C++模板编写之苦的同学们可以感受一下D语言的模板,下面先展示一个D语言编写的多分派委托类,在我的旧BLOG上曾经写过一个C++版本的,整个过程感觉非常痛苦。。。 闲话少说,请看代码: import std.stdio; template DelegateHandlers(HandlerType, FunctionType) {     Handl...

头脑歪歪 251

SAP采购订单行项目增强实战:用BADI ME_GUI_PO_CUST添加自定义字段(避坑指南)

本文详细解析了如何通过BADI ME_GUI_PO_CUST在SAP采购订单行项目中添加自定义字段,包括技术架构理解、字段扩展步骤、自定义函数组创建及BADI实现。文章特别强调了避开官方文档未提及的陷阱,如字段映射限制和屏幕显示问题,并提供了高级优化技巧和性能建议。

weixin_30402343的博客 595

用Proteus8.9自带STM32F401VE的Controller仿真STM32F407ZGT6,F429IGT6

@用Proteus8.9自带STM32F401VE的Controller仿真STM32F407ZGT6,F429IGT6 一, 目前得到的 Proteus8.9版本软件能够支持的Cortex-M4固件库项目,只能到达STM32F401VE (如下图1所示)。 (图1) 作为ST公司Cortex-M4更为广泛应用的F407,F429系列芯片;现在的Proteus8.9版本软件还没有固件库支持,不能...

kaillen的博客 3万+

D语言中的混入型模板

D语言中的混入型模板基本语法模板声明模板调用模板范本mixin 表达式调试 基本语法 模板声明 mixin template 识别名 模板参数 约束条件(可选) { 内容 } 模板可通过参数及约束条件进行重载 模板调用 mixin 模板识别名 模板参数(可选) 识别名(可选) 通过模板识别名可以直接调用模板,或通过新建一个识别名来调用模板内容 模板范本 mixin template Foo(size_t addr,T) // 声明模板 { size_t maddr = addr; // 传入参

sdv的博客 393

基于深度学习的茶叶等级检测识别系统:YOLOv10 + UI界面 + 数据集

YOLOv10是YOLO系列的最新版本,继承了YOLO模型的优点,并对速度和精度进行了优化。YOLOv10在目标检测中使用卷积神经网络(CNN)作为基础,通过改进网络结构和优化训练策略,实现了在更低的延迟下进行高精度的目标检测。本文详细介绍了基于YOLOv10的茶叶等级检测与识别系统的设计与实现过程。我们从数据集准备、模型训练与推理、UI界面设计等多个方面进行了详细讲解,并给出了相应的代码实现。通过本系统,我们可以高效地自动检测茶叶的等级,并通过UI界面直观地展示结果。

YOLO 765

46用d编程深入模板

原来模板章仅包含(函数,结构,类)模板和类型模板参数. 快速语法.D模板,易定义和使用.更可读,很强大.定义函数,结构,类的模板,只需要提供模板参数列表. T twice(T)(T value) { return 2 * value; } class Fraction(T) { T numerator; T denominator; // ... } 上面为快...

个人进步之路 581

项目管理 Agent:进度追踪与风险预警 Harness

我们先从LangChain的Agent定义说起:Agent是一个能感知环境、自主决策、调用工具、执行动作、迭代反思的智能实体。而「项目管理全自主Agent」,就是把Agent的核心能力和项目管理的五大过程组(启动、规划、执行、监控、收尾)深度结合,聚焦执行监控阶段的两个核心痛点:进度偏差自动化计算、风险信号自动化识别与预警的专门化Agent。全感知(Omnisensing):能从。

AI架构师小马 518

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

2401d,d的插值串,1027与1036哪个好

2401d,d的插值串,1027与1036哪个好

个人进步之路 400

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

32用d编程模板

模板可编写通用算法/数据结构 d模板非常强大.函数,结构,类模板. import std.stdio; void printInParens(T)(T value) { writefln("(%s)", value); } void main() { printInParens(42); // with int printInParens(1.2);...

个人进步之路 560

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

d继承链中忽略了模板插件

import core.stdc.stdio; class A { void visit(int a){ printf("A - int ");} void visit(float b) { printf("A - float ");} } mixin template Bmix(AST) { // 移动进B override void visit(int a) {printf("B - int ");} override void visit(float b)

sebeefe的博客 121

D语言模板最近的一些改进

不知道什么时候加入了“函数模板参数类型推导”和“类模板(改进型)”,文档中也是悄悄出现了。 函数模板参数类型推导: template Square(T){ T Square(T t) { return t * t; }} 以前调用时必须显式实例化: writefln("The square of %s is %s", 3, Square!(int)(3));现在可以使用自...

头脑歪歪 179

D语言泛型

比C++容易的泛型。看看下面简单的例子:module testContainer; import std.stdio; import std.container; void main(){ SList!int myList; foreach(i;0..10){ myList.insert(i); } foreach(element;myList){ writeln(element); } }现在来

Dean Chen的专栏 3572

无涯教程-D语言 - 模板(Templates)

模板是通用编程的基础,它涉及以独立于任何特定类型的方式编写代码。

无涯教程 96

2502d,模板类型推导

2502d,模板类型推导

个人进步之路 282

2607d,重载集加模板

2607d,重载集加模板

个人进步之路 506

d模板元编程笔记02

元 元名(T,U,V) 如 (限制条件 T, U 或 V) { ... } 元 限制(T) 如 (是(T : 整)) { /*...*/ } // #1 元 限制(T) 如 (是(T : 串)) { /*...*/ } // #2 元 限制(T,U) 如 (是(T : 整) && !是(U : 浮)) { /*...*/ } // #3 元 限制(T,U) 如 (是(T : 整) && 是(U : 浮)) { /*...*/ } //

个人进步之路 539

无涯教程-D语言 - 混合(Mixins)

Mixins是允许将生成的代码混合到源代码中的结构, Mixins可以是以下类型-

无涯教程 218
上一篇: D语言中的运算符重载
下一篇: D语言中的混入(Mixin)
uframer
博客等级 码龄22年 16粉丝 40原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值