一个奇怪的结构体

会思考的草 2011-09-21 04:31:42

template <typename T, typename U>
struct IsConvertibleToType
{
// preparation
typedef char ConvertibleResultType;
struct UnconvertibleResultType
{
char m_internal[2];
};

// one of these functions is chosen depending on whether T is convertible to U
static ConvertibleResultType Test(U); //两个重名的对象?
static UnconvertibleResultType Test(...);//是不定数参数列表么?

static T MakeT();

// actual test
enum { Value = sizeof(Test(MakeT())) == sizeof(ConvertibleResultType) };
};
...全文
306 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
立行 2011-09-23
  • 打赏
  • 举报
回复
值得学习,Mark一下
ri_aje 2011-09-22
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 yanran_hill 的回复:]

上面的说法是没错,可是总觉得似乎不太简洁,也许是俺做C#做的太多了,总是不自然的想这样写:

enum ...{value = (typeof(U).ToString() == typeof(T).ToString())


我记得在linux上是有typeof这个运算符的,能不能象上面的C#那样写代码呢?
[/Quote]
标准 C++ 没有 typeof,某些编译器有此扩充。假设使用这种编译器扩充。你的方法也只能在 T 和 U 是同样类型的时候成立。而主楼程序的意图是检测类型 T 能否 convert 为类型 U。convertible 的概念涵盖了相同的类型,也包含了 C++ 标准允许的其他方式的类型转换,比如 T == int, U == double. 对于这种情况,typeof(U).ToString() == typeof(T).ToString() 会给出假值,而主楼程序会给出真值。
ri_aje 2011-09-22
  • 打赏
  • 举报
回复
还得更正一下,不是“虚汗数”,是虚函数 (virtual function),我这输入法比较弱智。
ri_aje 2011-09-22
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 yanran_hill 的回复:]

哈,要是这么说的话,那使用C#更能解决这类问题了,C#支持interface接口定义,所以可以在interface封装GetType接口函数,只需要在类里面重写并调用GetType方法,返回基类名称或者直接返回一个不混淆的名称就行了,这样说的话,C#代码的可读性应该还算不坏呢,起码在处理这种问题的场合,能让人很快看懂
[/Quote]
C++ 也有虚汗数,不过是运行期的,楼主的程序是编译期的。我不会 C#,不知道你说的那些特性是运行期的还是编译期的(还是 C# 本来也不分这两个过程)。不过,说这些都没用,这里是 C++ 版。
  • 打赏
  • 举报
回复
typedef 类型定义嘛
赵4老师 2011-09-22
  • 打赏
  • 举报
回复
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
龙行天下之Sky 2011-09-22
  • 打赏
  • 举报
回复
mark一下,有时间仔细看看
yanran_hill 2011-09-22
  • 打赏
  • 举报
回复
哈,要是这么说的话,那使用C#更能解决这类问题了,C#支持interface接口定义,所以可以在interface封装GetType接口函数,只需要在类里面重写并调用GetType方法,返回基类名称或者直接返回一个不混淆的名称就行了,这样说的话,C#代码的可读性应该还算不坏呢,起码在处理这种问题的场合,能让人很快看懂
yanran_hill 2011-09-21
  • 打赏
  • 举报
回复
刚上完英语课,头脑还没适应过来,如果我的想法不可实现,大家就当什么也没发生好了
yanran_hill 2011-09-21
  • 打赏
  • 举报
回复
上面的说法是没错,可是总觉得似乎不太简洁,也许是俺做C#做的太多了,总是不自然的想这样写:

enum ...{value = (typeof(U).ToString() == typeof(T).ToString())


我记得在linux上是有typeof这个运算符的,能不能象上面的C#那样写代码呢?
ri_aje 2011-09-21
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 codewarrior 的回复:]
……
这就等于是利用编译器的特性来帮我们进行类型的判断?很巧妙啊。不过我还有一个疑问,为什么要声明函数MakeT?直接用sizeof(Test(T))==sizeof(ConvertibleResultType)不行吗?
[/Quote]

Test(T) 是函数声明,sizeof(Test(T))是语法错误,至少也得这样 sizeof(Test(T()))。
很不幸,这要求 T 的默认构造函数存在且 accessible,但并不是所有类型都满足这一点,比如

class T { T (); }; or struct T { T (int); };

都会造成 Test(T()) 中 T() 的失败,因此你提出的设计具有不期望的局限性。相比之下,static T MakeT (); 就没有这种问题,因为程序的设计意图只是需要类型 T,并不关心他如何构造以及是否在当前环境下可构造。
pengzhixi 2011-09-21
  • 打赏
  • 举报
回复
额 宏的替换是预编译期,在编译期之前。替换之后所有的错误都可以在编译期体现出来。
会思考的草 2011-09-21
  • 打赏
  • 举报
回复
看上去这段代码是利用模板的特性,整个判断都是在编译期完成的,我还有另一个疑问,这段代码是一个错误检查宏的一部分,错误检查宏是在运行期才会执行的,这两者似乎时间是岔开的,如何能起作用?
会思考的草 2011-09-21
  • 打赏
  • 举报
回复
哦,那么sizeof(Test(MakeT()))的意思是:
MakeT返回T类型,用T作为参数去调用Test,如果编译器认为T类型等于U类型,那么根据重载的规则,编译器就会调用Test(U),否则就是调用Test(...)啰?
所以如果Test(MakeT())实际对应的是Test(...),则返回的是UnconvertibleResultType类型,必定和Test(U)的返回类型不一致,Value=false;如果Test(MakeT())对应的是Test(U),那么返回类型是一致的,Value=true。

这就等于是利用编译器的特性来帮我们进行类型的判断?很巧妙啊。不过我还有一个疑问,为什么要声明函数MakeT?直接用sizeof(Test(T))==sizeof(ConvertibleResultType)不行吗?
yanran_hill 2011-09-21
  • 打赏
  • 举报
回复
所以我觉得,楼主说的应该有道理,貌似算是比较奇怪的结构体呢
pengzhixi 2011-09-21
  • 打赏
  • 举报
回复
哪一行?
yanran_hill 2011-09-21
  • 打赏
  • 举报
回复
没看明白这么写有什么必要性,而且阅读起来似乎比较吃力
yanran_hill 2011-09-21
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 pengzhixi 的回复:]

因为这里根本就不需要实现。sizeof只会对表达式最终的类型进行计算大小,而不会对表达式进行任何求值。这个计算是编译期的。
[/Quote]
解释倒是能解释通,不过这一行代码为什么要这样写?
---------------------------------------------------------------------
static ConvertibleResultType Test(U); //两个重名的对象?
static UnconvertibleResultType Test(...);//是不定数参数列表么?

static T MakeT();

// actual test
enum { Value = sizeof(Test(MakeT())) == sizeof(ConvertibleResultType) };
--------------------------------------------------------------------
这么些没看明白有什么必要性,而且阅读起来似乎比较吃力
就想叫yoko 2011-09-21
  • 打赏
  • 举报
回复
sizeof 实际上求的是函数返回类型的大小
pengzhixi 2011-09-21
  • 打赏
  • 举报
回复
因为这里根本就不需要实现。sizeof只会对表达式最终的类型进行计算大小,而不会对表达式进行任何求值。这个计算是编译期的。
加载更多回复(7)
这个源码没记错的话是去年9月份写的,当时本来是打算写一个功能齐全一点的PE工具,例如解析导入表、导出表、重定位表及节表等功能,后来只写了一个解析导出表就放弃了,为什么呢,主要是因为声明结构体比较烦,是一个体力活,所以后面转用VS开发这款工具去了,毕竟头文件里都将结构体定义好了,省事,现在把这个 易语言 版本的解析导出表代码开源。 它可以解析出导出表里正常导出的函数,还能解析出导出表里的中转函数,见下图: 写这个工具的过程中发现PEID解析导出表有点问题,见下图 注意这个图里3个红框里的内容,第一个是LORDPE解析的,中间是我自己写的代码解析的,最右边是PEID解析的,可以发现PEID解析导出表时只能正常解析以符号名导出的函数,一旦遇到以序号导出的函数就会导致错位,图中user32.dll导出的前两个函数是以序号0x5DC和0x5DD导出的并没有导出函数名,而PEID不能正常解析,LORDPE、STUDYPE还有我自己写的代码都能正常解析,至于为什么导出序号那里,我的是从0开始的,而LORDPE和STUDYPE是以0x5DC开始的,那是因为我没有加上序号基数,中间那个蓝色箭头指向就是基数,函数真正的导出序号是要加上这个基数的,只不过我习惯这样表达而已。另外开源前特意把里面变量的名字改成了一看就明白的意思,所以看起来有点奇怪

64,647

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧