typedef struct 先声明后定义_C++模版和C#泛型求同存异录(二)typedef
(这篇文章有些复杂,请来回慢慢看)
typedef
C++语言中的typedef简直是个神奇的关键字,它的最简单的作用就是把一种类型重新命名,定义个别名。很像宏定义,但又不是。在编程中使用typedef目的一般有两个,一个是给变量定义一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。但在C++模版编程之中,它还有个非常巧妙的用处:类型之间的传递和约束!
C++ typedef
来看个例子(真的用的好开心)
template <class T>
class Matrix
{class Accessor{public:typedef T DATATYPE;}
}template <typename ACCESSOR>
class Scanner
{public:typedef typename ACCESSOR::DATATYPE DATATYPE;
}
一个简单的使用例子是这样的
typedef float DATATYPE;
Matrix<DATATYPE> data; //数据源
Matrix<DATATYPE>::Accessor accessor(data); //访问器
Scanner<Matrix<DATATYPE>::Accessor> scanner(accessor) //检索器
请问Scanner::DATATYPE是什么数据类型?答案就是float!
也就是说,上面的案例之中,两个模版类的数据类型出现了传递,类型出现了相互依赖的关系。以上代码如果不做特殊设计,那么就只能写出这样的代码了
typedef float DATATYPE;
Matrix<DATATYPE> data;
Accessor<DATATYPE> accessor(data);
Scanner<DATATYPE> scanner(accessor)
逻辑是明白的,但是相互的依赖关系是要靠约定的,而不是代码本身能控制的。仅是typedef的巧妙使用,使得 T->Accessor::DATATYPE->Scanner::DATATYPE
,数据类型出现了传递行为。也就是说通过typedef,使的Scanner::DATATYPE
,Matrix::Accessor::DATATYPE
,DATATYPE
,float
都是相同的类型,只是别名不同而已。这些不同的别名拥有不同的语义,且存在相互依赖关系。
类型传递?
那么更加进一步问题来了,C#能做到这个吗?
首先C#没有typedef关键字,也没有typename关键字,所以似乎我们只能写出最直白的代码(忽略using关键字定义别名的功能,这个功能太弱)
class Matrix<T>
{class Accessor{Accessor(Matrix<T> matrix){}}
}
class Scanner<T>
{Scanner(Matrix<T>.Accessor accessor){}
}Matrix<float> data;
Accessor<float> accessor(data);
Scanner<float> scanner(accessor)
这样的代码显然只能依赖于程序员不能犯错,而从代码本身角度来说,也是缺乏一些类型约束功能。
当然似乎这样的代码也不会出错,因为C#是强类型的,如果我们这样写
Matrix<int> data;
Accessor<float> accessor(data); //会报错,会提示无法从Matrix<int>转换成Matrix<float>
Scanner<float> scanner(accessor)
但是我期望的代码至少是
Matrix<float> test = new Matrix<float>();
Matrix<float>.Accessor accessor(data);
Scanner<Matrix<float>.Accessor> scanner(accessor)
让我们把C++的设计思路直接用在C#版本
尝试过程跳过,我给出一个最接近的版本。用到关键字dynamic,where,不懂的同学请自己查下帮助文档。
public class AccessorBase
{public dynamic value;
}public class Matrix<T>
{public class Accessor : AccessorBase{public new T value;}
}public class Scanner<Accessor> where Accessor : AccessorBase
{public Scanner(Accessor accessor){value = accessor.value;}private dynamic value; public dynamic GetValue() { return value; }
}
简化过的测试代码如下
Matrix<float>.Accessor accessor = new Matrix<float>.Accessor();
accessor.value = (float)99.0;
Scanner<Matrix<float>.Accessor> scanner = new Scanner<Matrix<float>.Accessor>(accessor);
dynamic tmp = scanner.GetValue(); //tmp的值为null,但是我希望是99.0
问题出在 value = accessor.value; 这一句代码中 因为Accessor和AccessorBase的value只能保留一个。
不用where,那么accessor.value无法调用,除非使用反射。或者使用dynamic关键字
public Scanner(dynamic accessor)
{value = accessor.value; //但accessor缺乏类型约束
}
反正我试了好久没有啥解决办法。回到C++的typedef功能 typedef
那么我们能在C#中模拟出来typedef吗,结论是可以!
直接上代码
public abstract class Typedef<T, TDerived> where TDerived : Typedef<T, TDerived>, new()
{private T _value;public static implicit operator T(Typedef<T, TDerived> t){return t == null ? default : t._value;}public static implicit operator Typedef<T, TDerived>(T t){return t == null ? default : new TDerived { _value = t };}
}
这是适合任何类型重定义的类。
class DATATYPE : Typedef<double, DATATYPE> { };
class SDATATYPE : Typedef<DATATYPE, SDATATYPE> { };
缺陷是DATATYPE和SDATATYPE是两个完全不同的类,因为C#是强类型。使用起来有些别扭
DATATYPE data = (DATATYPE)99.0;
SDATATYPE sdata = (SDATATYPE)(DATATYPE)99.0;
先忽略这一点,让我们看看前面的泛型代码该怎么改
默默测试两天之后,我发现,就算模拟了一个typedef的操作,依然还是做不到类型传递。
因为C#没法写出类似下面的代码
typedef typename ACCESSOR::DATATYPE DATATYPE;
typename ACCESSOR::DATATYPE是告诉C++编译器,ACCESSOR::DATATYPE是类型,虽然这个类型现在不知道是什么类型,但是就是个类型。然后C#可做不到这样的事情,所以只能是黑人问好脸了。
最后我又只能回到最初的代码,依赖于C#的强类型,保证在相互之间传递数据的时候,不会出错:
class Matrix<T>
{class Accessor{Accessor(Matrix<T> matrix){}}
}
class Scanner<T>
{Scanner(Matrix<T>.Accessor accessor){}
}Matrix<float> data;
Accessor<float> accessor(data);
Scanner<float> scanner(accessor)
后记
文章写完了,为了探索这个可能性,我大概花费了3-4个晚上的休息时间。虽然路是不通的,但也对C#泛型和C++的模板代码的设计思路更进一步了解了差异性。虽然这不算是什么成绩,但我还是把整个过程整理了一篇文章。
虽然Typedef 效果没有我设想的那么完美,但依然是一个很有效的typedef用法,特别可以支持任何Primitive类型,sealed class的继承操作,这一点还是值得一提的。
Github有个类似功能很小的C#库,叫LikeType,https://github.com/kleinwareio/LikeType 如果谁有兴趣可以仔细去看下,它也实现了类似的功能。
完
最后修改于2019-12-17日,首发于公众号:技术宅指北
typedef struct 先声明后定义_C++模版和C#泛型求同存异录(二)typedef相关推荐
- C++模版和C#泛型求同存异录(一)sizeof(T)
sizeof(T) 从C++的模板代码往C#代码移植的时候发现了一个小问题. 在C++模板代码中 sizeof(T)是一种有效的写法,最终在会编译器展开成sizeof(int),sizeof(floa ...
- 全局声明宏定义_C++模拟面试:宏、lambda、智能指针闲谈
有时候出于种种目的,我们会用宏来写一些函数.有人称之为宏函数.下面我们来模拟一场面试: 面试官 自来也 先来个简单的热热身,用宏实现求两个数最大值. 刷刷刷 #define MAX(x, y) ((x ...
- 【Struct(结构体)杂谈之二】名不正则言不顺---Struct(结构体)的声明、定义及初始化
Struct(结构体)的声明.定义及初始化 上一篇里我们讲了为什么我们要引入Struct这个数据类型,我们了解到Struct是一种聚合数据类型,是为了用户描述和解释一些事物的方便而提出的,Struct ...
- typedef struct与struct的区别
第一篇:typedef struct与struct的区别 1. 基本解释 typedef为C语言的关键字,作用是为一种数据类型定义一个新名字.这里的数据类型包括内部数据类型(int,char等)和自定 ...
- c语言中的typedef struct相当于java的一个类?,C ++中'struct'和'typedef struct'之间的区别?...
在C ++中,之间有什么区别: struct Foo { ... }; 和 typedef struct { ... } Foo; #1楼 您不能对typedef结构使用forward声明. stru ...
- C/C++语法知识:typedef struct 用法详解
第一篇:typedef struct与struct的区别 1. 基本解释 typedef为C语言的关键字,作用是为一种数据类型定义一个新名字.这里的数据类型包括内部数据类型(int,char等)和自定 ...
- 声明 struct x1 { ...}; 和 typedef struct { ...} x2; 有什么不同?
声明 struct x1 { ...}; 和 typedef struct { ...} x2; 有什么不同? 第一种形式声明了一个 ``结构标签''; 第二种声明了一个 ``类型定义''. 主要的区 ...
- 【C语言】结构体定义 typedef struct 用法详解和用法小结
结构体定义 typedef struct 用法详解和用法小结 文章目录 结构体定义 typedef struct 用法详解和用法小结 0. 前言 1. 首先:在C中定义一个结构体类型要用typedef ...
- 关于数据结构(c语言)中结构体声明的typedef struct LNode, *LinkList的思考
在数据结构的链表,表示中 typedef struct Node * PtrToNode 和 typerdef struct List的表示说明 typedef struct Node * PtrTo ...
最新文章
- miniz库简介及使用
- CasperJs 入门介绍
- linux为启动菜单加密码
- Memcached简介
- Java PrintWriter close()方法与示例
- 架构设计 | 缓存管理模式,监控和内存回收策略
- 相机下载_索尼黑卡相机与手机互联APP相关
- Windows编程的Notification和Message
- vue ---- webpack中loader
- [Unity]Curvy插件随机生成装饰物
- SecureCRT配置详细图文教程
- val.substring is not a function
- C++算法之选择排序
- 建立时间setup time/保持时间 hold time
- python之奇数和或偶数和
- ERP系统的主要功能模块
- java实现倒计时闹钟_倒计时闹钟软件下载-倒计时闹钟app下载v1.2.4-西西软件下载...
- 一卡通系统中的前置机的设置
- 望帝春心托杜鹃 中望帝的由来~
- AutoCAD对象模型