在C++中实现类型演算---(ajoo, hyifeng请进)

smilemac 2003-11-01 04:49:41
程序其实前天就写出了,但其中对参加演算的类型有一个size不能相同的限制,我想了很久也没有想出解决的办法,因为无法将一个对象token在编译时引入模版类中,但好在ajoo没有说不可以对类型作限制,所以虽然还不是太完美,但马马虎虎也可以交差了:-),所以是被该给我200大元了,呵呵,另外也一起想想可不可以作的更通用一些。下面的程序在VC7.0上作了简单的测试(也可能不够完全)。两位不妨试试。

//EnvaType.h
#pragma once

#include "..\loki\TypeList.h"
using namespace Loki;
using namespace Loki::TL;

namespace EnvaType
{
template <class TL, int Size>
class EnvaType
{
public:
template <int Index>
struct IndexOfEnvaType
{
typedef typename TypeAt<TL,Index>::Result Type;

enum { value = sizeof(Type) == Size ? Index : IndexOfEnvaType<Index-1>::value };
};

template <>
struct IndexOfEnvaType<-1>
{
enum { value = -1 };
};

private:
enum { length = Length<TL>::value };
enum { index = IndexOfEnvaType<length-1>::value };

public:
typedef typename TypeAt<TL,index>::Result Result;
};

template <typename T>
void IsConvertible(const T& obj){return ;};


#define TYPE_FROM_INFER(TL, newObj, obj) ::EnvaType::EnvaType<TL,sizeof(obj)>::Result
#define TO_INFER(TL, newObj, obj) TYPE_FROM_INFER(TL, newObj, obj) newObj
#define INFER(TL, newObj, obj) TO_INFER(TL, newObj, obj);\
IsConvertible<TYPE_FROM_INFER(TL, newObj, obj)>(obj);\


};
//end of file EnvaType.h


//MyTest.h
#pragma once

#include <iostream>
using namespace std;

namespace MyTest
{
struct CTestA
{
char _val[1];

void whoami(void)
{
cout << "I am A" << endl;
}
};

struct CTestB
{
char _val[2];

void whoami(void)
{
cout << "I am B" << endl;
}
};

struct CTestC
{
char _val[40];

void whoami(void)
{
cout << "I am C" << endl;
}
};

CTestA MakeO(float n)
{
return CTestA();
}
CTestB MakeO(double n)
{
return CTestB();
}
CTestC MakeO(char n)
{
return CTestC();
}

using namespace EnvaType;

#define TL_TEST TYPELIST_3(CTestA, CTestB, CTestC)

#define MyINFER(name, obj) INFER(TL_TEST, name, obj)

};
//end of file MyTest.h


//main.h
......
cout << "EnvaType testing start ..." << endl;

CTestB a;
MyINFER(newa, a);
newa.whoami();

MyINFER(newo, MakeO((float)0));
newo.whoami();

......

//end of test



...全文
52 48 打赏 收藏 转发到动态 举报
写回复
用AI写文章
48 条回复
切换为时间正序
请发表友善的回复…
发表回复
birth_chen 2003-11-06
  • 打赏
  • 举报
回复
mark
ajoo 2003-11-06
  • 打赏
  • 举报
回复
我把连接贴在这吧,以避免某些人继续拿别人的东西招摇撞骗。

代码都在这里,大家可以自己下载研究。其实关键的就是一个typeint的实现。作者自己也说了,这就是一个研究,并不一定很实用。
它也不能完整解决INFER的问题,因为用户仍然需要自己登录自定义类型。而这个根本的鸿沟只有通过语言本身的支持来解决,gcc就实现了typeof的扩展。

http://www.semantics.org/code.html


smilemac 2003-11-05
  • 打赏
  • 举报
回复
plainsong,

你的方法确实很好,不过最后需要再加一步根据size大小判断返回的类型是否正确的操作,因为可能存在不在Typelist里的类型。我的方法要比你的复杂很多,没你的好。
ajoo 2003-11-05
  • 打赏
  • 举报
回复
plainsong,一般流行的做法是返回char(*)[size]。
这样,sizeof(*type_of(e))就可以得到真正的大小了。它和你的type_of_size<size> 相似,只不过,不需要用复杂的模板类型。

smilemac,我还在等待你的道歉。争执也好,你更喜欢那个招摇撞骗的骗子教育大家的讨论方式也好,无所谓。你不喜欢我评价你的代码无所谓,不喜欢我个人也我所谓。

但是,既然打了赌,大家也都说了公道话,不知道你是否准备给我个交待?
hyifeng 2003-11-05
  • 打赏
  • 举报
回复
在这里先谢谢cnswdevnet。
hyifeng 2003-11-05
  • 打赏
  • 举报
回复
//
// Copyright (c) 2002 by Stephen C. Dewhurst
// Permission to use, copy, modify, distribute and sell this software for any purpose is
// hereby granted without fee, provided that the above copyright notice appears in all copies
// and that both that copyright notice and this permission notice appear in supporting documentation.
// The author or makes no representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//

// "typeof" operator implementation
//
// Described in CUJ 20(8, 10, and 12), August, October, and December 2002: "A Bit-Wise Typeof"
//


以上是cnswdevnet(跟皮虫)发给我的typeof.h的头描述。
果然是比较长,一时我也没有耐性看(能力有限),大家要不要我贴出来一起研究一下,算是学习,也算是辨别真伪。

如何?
smilemac 2003-11-05
  • 打赏
  • 举报
回复
是指派生类或其他兼容类型。
xueweizhong 2003-11-04
  • 打赏
  • 举报
回复
海纳百川,有容乃大。
我还是从这里学到了大家的很多精彩见解。
希望继续聆听大家的高见,而不要因为言语之争而失去了
进步的机会。
ajoo 2003-11-04
  • 打赏
  • 举报
回复
其实,感觉测试这类自制的typeof,只需要关心两点:
1。是否要求自己登记自定义类型。比如说:
struct My{};
是不是一定要REGISTER(My)之后才可以typeof(My()) m;

2。是否对自定义类型有比较苛刻的要求,比如说,可不可以处理:
char**************************************************************** p;
typeof(p) p2;

可不可以处理:

template<template<typename> class F, typename T>struct TypeConstructor{
template<int i>struct Construct{
typedef Construct<i-1>::Apply Apply;
};
template<>struct Construct<0>{
typedef F<T> Apply;
};
};
template<typename T>struct TypeUnit{
typedef T Type;
};
typeof(TypeConstructor<TypeUnit, int>::Construct<130>::Apply()) a;


短歌如风 2003-11-04
  • 打赏
  • 举报
回复
应该是IndexOf<TL,T>::Result + 1,这样可以避免T不在TL中时(-1)导致深度递归的模板实例化。

不过有些问题:在BCB中好象无法处理type_of_size<IndexOf<TL,T>::Result +1>这样复杂的返回值,而在Dev C++中,对下面的模板偏特化也无法适应:
template <typename T>
struct type_of_stub;

template <typename T>
struct type_of_stub<Int2Type<sizeof(<+1>)> >
{
typedef T _type;
};
它还是用了非特化版本。
只能利用sizeof(type_of_size<I>)/sizeof(type_of_size<0>) = I + 1这个规律恢复出IndexOf<TL,T>::Result再到TL中把类型取出来了。

此外,Type2Int并不是实现typeof必须的,只是这种方法中才是必须的。据说下一版本的标准会把typeof包含到语言中。毕竟由语言实现比用类库实现容易的多,就象Andrei所说,它和sizeof拥有相同的后端实现,只是sizeof把类型信息扔掉了。

不过我觉得typeof的实用性可能还比不上Type2Int。
yjh1982 2003-11-04
  • 打赏
  • 举报
回复
可惜.__LINE__在VC中工作异常:
扩展为:
__FUNCTIONLINE__+__FUNCTIONOFFSET__
ajoo 2003-11-04
  • 打赏
  • 举报
回复
plainsong提出的方法其实是很有价值的。如果自己做typeof,也许归根结蒂最关键的还是做这个type到int的映射吧。

其实呢,要是要求程序员必须手工登录类型。(库当然可以预先登录一些类型,但是不可能穷尽所有的可能性),也不需要一定依赖类型的大小的。
最简单地,只要所有的登录都在一个文件里,使用__LINE__这个宏,就可以自动生成唯一的type id。有了这个id,按照类似plainsong提到的方法(或者用通常用的返回数组的方法,可以避免对编译器提出太高的要求),也就可以构建一个更好的typeof了。
当然,这样就逐渐复杂起来了。而且,这也不能适应登录模板的需要。


更复杂的type2int机制,也许需要使用类似位操作的整数操作来避免type id对声明顺序的依赖,这类的做法,也许可以对付登录模板之类的自定义类型组合的需要吧。可是,我怀疑这样的机制能否很通用。毕竟,整数的值空间是有限的,位数更是有限的。理论上,不可能提出一种能够完全映射所有类型的机制。

如果使用__LINE__,因为实际上不大可能出现超过整数表达范围的类型数,应该还可以应付。但是如果使用更结构化的方式来做type->int的映射的话,浪费值空间来给某类属性保留指定位域只怕很难免。
到时候,只怕就会有什么模板嵌套深度不能超过16层,模板参数个数不能超过32个等等这种限制了。
而这种限制,对做expression template的公式,或者做io formattor都很致命。




对了。网上是有一些试图用代码来实现typeof功能的尝试。
但是,没有compiler的支持,这些努力都还是需要程序员手工登录类型或者模板。

就我的这个要求来说,INFER(v,f(...)), 如果f()是一个模板函数,返回类型依赖于传入的参数类型,而参数类型又可以是用户自定义的,就象makeGuard一样,
那么,这就意味着用户必须自己手工登录自己定义的每个类型甚至可能需要登录每个可能返回的类型(而我们就是在尽力避免明确写出返回类型)。这点,我认为对用户来说是难以接受的问题。

至于某些人在网上下载了别人写的库,还没读明白代码就以为捡到了万应灵丹,这种可笑的骗子嘴脸大家都看得见,我就不用多废话了。
ajoo 2003-11-04
  • 打赏
  • 举报
回复
上面是三行代码,
不过,考虑到c++的typedef语法有时候有些怪异的情况,可以稍微加一个wrapper:
template<typename T>
struct TypeId{typedef T id;};

然后,把DECL_TYPE改成:
#define DECL_TYPE(t) template<>struct TypeOf<sizeof(t)>{typedef TypeId<t>::id type;};

也就是五行了。
ajoo 2003-11-04
  • 打赏
  • 举报
回复
呵呵。接受大家的批评。plainsong, pongba, hyifeng,你们说的都很对。

老实说,我写了这个比较激烈的回复后,也有点后悔。当时就是觉得smilemac在故意捣鬼赖帐。网上又没有办法真正找人仲裁,就有些生气了。现在想想很无谓的。

smilemac,我对我的话里面的过分之处表示歉意。不过,我坚持认为你欠我一个正式的道歉。这不是风度不风度的问题,既然打了赌了,就要愿赌服输。

我说三五行可以做出来也不是顺口胡吹。我想不只是我,plainsong他们也一样可以写出来的。
因为它本来就很简单,就是一个模板特化而已:
template<int i>struct TypeOf{};
#define DECL_TYPE(t) template<>struct TypeOf<sizeof(t)>{typedef t type;};
#define type_of(exp) TypeOf<sizeof(exp)>::type
然后,象你的type list一样自己登记一些大小不同的类型就可以了。
DECL_TYPE(int)
DECL_TYPE(char)
...


使用的时候,就
type_of(1) i;
不是也达到了你这个东西的同样的功能?同样,你要是试图登记两个大小一样的类型,也可以报错的。


hyifeng 2003-11-04
  • 打赏
  • 举报
回复
plainsong已经提出了一个支持受限类型的infer方案

template<int S>
struct type_of_size
{
type_of_size<S-1> bytes;
char byte;
};

template<>
struct type_of_size<0>
{
char byte;
};

typename<typename TL,typename T>
type_of_size<IndexOf<TL,T>::Result> type_to_size(const T&);

#define typeof(TL,obj) TypeAt<TL,sizeof(type_to_size<TL>(obj))-1>::Result

谁能提出不手工创建typelist的办法呢?
这条路能不能走下去。
smilemac 2003-11-04
  • 打赏
  • 举报
回复
真正的原因恐怕在于,不明白typelist在这里到底起什么作用.
smilemac 2003-11-04
  • 打赏
  • 举报
回复
呵呵,也想学cnswdevnet奉劝一下个别人,考虑问题要全面一些,多想想实际编程过程,多想想真正的问题到底有哪些,即使不得不引入约束,也要考虑如何将这种约束降至最低使得实际可操作,否则真的做了一个摆设玩具恐怕还不自知.

另外我已经想出了允许size相同的办法.
smilemac 2003-11-03
  • 打赏
  • 举报
回复
hyifeng,

150分或300分都不必乐,我也不是经常来csdn, 要分数也没用。根据对象作类型推演本来是有其实际价值(这也是让我认真对其试着写了一个实作的原因),某人却将之用来做避免写尖括弧、长类型名的用途,这十分可笑,所以我一开始对这样的要求也没太认真,只是将其作为一般的类型推演实作问题来考虑,但现在非要在这方面较真,所以我也想了些办法,但剩下的已经是毫无实际用途,而是纯粹游戏了。我们可以在email交换看法。
hyifeng 2003-11-03
  • 打赏
  • 举报
回复
hi,smilemac,我的提议怎么样,

“按现在这个实现我只能给你 150 分。
等你把剩下的工作做完,另外 150 分自然奉上。
或许你找到一个有意义的特例,是使用你的作品能很好的解决的,300分圆满奉上。”

给点回应呀。
yjh1982 2003-11-03
  • 打赏
  • 举报
回复
楼主的确没达到要求,事实上是不可能实现的
加载更多回复(28)

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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