摘要:
1。符号查找(对于函数此时只看名字,不看参数) 大致顺序是 (1)如果有限定名( XXX:: )那么就直接在XXX里查找 (2)函数局部名字空间 (3)(如果是成员)类名字空间 (4)递归向上至所有基类的...
阅读全文
posted @
2006-12-27 11:04 shifan3 阅读(2096) |
评论 (8) |
编辑 收藏
发信人: shifan (学习浮云技术), 板面: C++
标 题: 伪typeof
发信站: 飘渺水云间 (Tue Dec 19 16:38:45 2006), 转信
1 /*
2 用标准C++实现typeof是不可能的
3 这个是我写的一个approached typeof
4 所有需要被静态反射出来的类型必须先用DECL_TYPE注册
5 模板如果仅仅带有1个参数可以用DECL_TEMPLATE_1注册
6 多个参数的模板还不支持。。
7 主要是没想好编码
8
9 总共能注册64个类型
10 可以通过MAX_TYPE_NUMBER设置
11
12 支持的模板嵌套层数大约为32 / log2(MAX_TYPE_NUMBER)
13 MAX_TYPE_NUMBER必须为2的整次数幂
14 */
15 namespace my_typeof
16 {
17
18 const int MAX_TYPE_NUMBER = 64;
19
20 template <int N>
21 struct dummy
22 {
23 int a[N];
24 };
25
26
27 template <int N, typename Arg1>
28 struct select_by_number_1;
29
30 template <int N>
31 struct select_by_number
32 {
33 typedef typename select_by_number_1<N % MAX_TYPE_NUMBER, typename
34 select_by_number<N / MAX_TYPE_NUMBER>::type>::type type;
35 };
36
37
38 template <typename T>
39 struct number_of
40 {
41 static const int v = sizeof(generic_f(*(T*)0)) / sizeof(int);
42 };
43
44
45 #define DECL_TYPE(T, N) \
46 namespace my_typeof{ \
47 template<>\
48 struct select_by_number<N> \
49 {\
50 typedef T type;\
51 };\
52 dummy <N> generic_f(const T&);}
53
54
55 #define DECL_TEMPLATE_1(T, N) \
56 namespace my_typeof{ \
57 template<typename Arg1>\
58 struct select_by_number_1<N, Arg1>\
59 {\
60 typedef T<Arg1> type;\
61 };\
62 template <typename Arg1>\
63 dummy<N + number_of<Arg1>::v * MAX_TYPE_NUMBER > generic_f(const T<Arg1>&);}
64
65
66
67 #define TYPE_OF(x) my_typeof::select_by_number<sizeof(my_typeof::generic_f(x)) /
68 sizeof (int)>::type
69
70 }
71
72
73 //sample
74 #include <iostream>
75 #include <vector>
76 #include <list>
77
78
79 DECL_TYPE(int, 1);
80 DECL_TEMPLATE_1(std::vector, 2);
81 DECL_TEMPLATE_1(std::list, 3);
82 DECL_TYPE(double, 4)
83
84 using namespace std;
85 int main(int, char*[])
86 {
87 vector<list<vector<list<double> > > > v1;
88 TYPE_OF(v1) v2;
89 v1 = v2;
90 return 0;
91 }
92
93
--
You well 撒法!You well all 撒法!
※ 内容修改:·shifan 于 Dec 21 14:21:57 修改本文内容·[FROM: shifan]
※ 来源:·飘渺水云间 freecity.cn·[FROM: shifan]
posted @
2006-12-21 14:29 shifan3 阅读(2631) |
评论 (8) |
编辑 收藏
真令人伤感,每过几年就是离别时。
我站在窗前,无奈的看着朋友们为了工作奔走,
而不能帮上哪怕一点忙。
就像十年前,就像六年前,就像三年前
就像每一次与人擦肩而过却故意目不斜视。
但这一次也许好一点,毕竟我们以后可能还能时常相聚,
而不像现在只能看着从前的好友的博客独自伤感。
那种陌生,令人心碎。
posted @
2006-11-01 00:31 shifan3 阅读(579) |
评论 (4) |
编辑 收藏
boost的integer/integer_mask.hpp仅仅做了单个位的bit mask
要多个位必须写很多遍high_bit_mask_t
使用low_bits_mask_t也不能完全解决问题
所以自己用Typelist的那种写法写了一个
用法举例
bit_mask<INT_LIST_2(2, 3)>::value返回一个值,该值的第2、3位被置为1
其余位为0
1
2 namespace multi_bit_mask
3 {
4 namespace details
5 {
6
7 template <typename T>
8 struct get_size
9 {
10 enum {size = sizeof(T)};
11 };
12
13 template <int Bit>
14 struct bit_storage
15 {
16 typedef typename bit_storage<Bit - 1>::storage_type storage_type;
17 };
18
19 //---------platform dependency-----------------------
20
21 typedef unsigned int smallest_storage_type;
22 typedef unsigned long long largest_storage_type;
23
24
25
26 template <>
27 struct bit_storage<0>
28 {
29 typedef smallest_storage_type storage_type;
30 };
31
32 template <>
33 struct bit_storage<get_size<smallest_storage_type>::size * 8>
34 {
35 typedef largest_storage_type storage_type;
36 };
37
38 //disable the 65th bit
39 template <>
40 struct bit_storage<get_size<largest_storage_type>::size * 8>
41 {
42 typedef void storage_type;
43 };
44
45 //---------end of platform dependency----------------
46
47
48 template <unsigned int N, typename Next>
49 struct int_list
50 {
51 typedef typename bit_storage<N>::storage_type storage_type;
52 static const storage_type value = N;
53 typedef Next next;
54 };
55
56 struct null_type{};
57
58 template<typename T1, typename T2, bool is_first>
59 struct selector
60 {
61 typedef T1 type;
62 };
63
64 template<typename T1, typename T2>
65 struct compare_type
66 {
67 const static bool is_larger = sizeof(T1) > sizeof(T2);
68 typedef typename selector<T1, T2, is_larger>::type large_type;
69 typedef typename selector<T1, T2, !is_larger>::type small_type;
70 };
71
72
73
74 template<typename T1, typename T2>
75 struct selector<T1, T2, false>
76 {
77 typedef T2 type;
78 };
79
80 template <typename List>
81 class find_largest_storage
82 {
83 typedef typename find_largest_storage<typename List::next>::storage_type T1;
84 typedef typename bit_storage<List::value>::storage_type T2;
85 public:
86 typedef typename compare_type<T1, T2>::large_type storage_type;
87 };
88
89 template <>
90 class find_largest_storage<null_type>
91 {
92 public:
93 typedef smallest_storage_type storage_type;
94 };
95
96
97 }
98
99
100
101
102
103 template <int N>
104 struct single_bit_mask
105 {
106 typedef typename details::bit_storage<N>::storage_type storage_type;
107 static const storage_type value
108 = static_cast<storage_type>(single_bit_mask<N - 1>::value) * 2;
109 };
110
111 template <>
112 struct single_bit_mask<0>
113 {
114 typedef details::bit_storage<0>::storage_type storage_type;
115 static const storage_type value = 1;
116 };
117
118
119 typedef details::null_type null_type;
120
121 template <int N, typename Next>
122 struct int_list_t : public details::int_list<N, Next> {};
123
124 template <typename List>
125 struct bit_mask
126 {
127 public:
128
129 typedef typename details::find_largest_storage<List>::storage_type storage_type;
130
131 static const storage_type value
132 = static_cast<storage_type>(single_bit_mask<List::value>::value)
133 | static_cast<storage_type>(bit_mask<typename List::next>::value);
134 };
135
136 template <>
137 struct bit_mask<null_type>
138 {
139 typedef details::bit_storage<0>::storage_type storage_type;
140 static const storage_type value = 0;
141 };
142
143
144
145
146
147 #define INT_LIST_1(n1) multi_bit_mask::int_list_t<n1, multi_bit_mask::null_type>
148 #define INT_LIST_2(n1, n2) multi_bit_mask::int_list_t<n1, INT_LIST_1(n2) >
149 #define INT_LIST_3(n1, n2, n3) multi_bit_mask::int_list_t<n1, INT_LIST_2(n2, n3) >
150 #define INT_LIST_4(n1, n2, n3, n4) multi_bit_mask::int_list_t<n1, INT_LIST_3(n2, n3, n4) >
151 #define INT_LIST_5(n1, n2, n3, n4, n5) multi_bit_mask::int_list_t<n1, INT_LIST_4(n2, n3, n4, n5) >
152 #define INT_LIST_6(n1, n2, n3, n4, n5, n6) multi_bit_mask::int_list_t<n1, INT_LIST_5(n2, n3, n4, n5, n6) >
153 #define INT_LIST_7(n1, n2, n3, n4, n5, n6, n7) multi_bit_mask::int_list_t<n1, INT_LIST_6(n2, n3, n4, n5, n6, n7) >
154 #define INT_LIST_8(n1, n2, n3, n4, n5, n6, n7, n8) multi_bit_mask::int_list_t<n1, INT_LIST_7(n2, n3, n4, n5, n6, n7, n8) >
155
156 }
157
158
159
sample
#include < iostream >
#include " multi_bit_mask.h "
using namespace std;
int main()
{
cout << multi_bit_mask::bit_mask < INT_LIST_1( 1 ) > ::value << endl;
cout << multi_bit_mask::bit_mask < INT_LIST_5( 0 , 1 , 2 , 3 , 4 ) > ::value << endl;
cout << multi_bit_mask::bit_mask < INT_LIST_7( 0 , 1 , 2 , 3 , 4 , 4 , 2 ) > ::value << endl;
posted @
2006-10-26 23:37 shifan3 阅读(1435) |
评论 (2) |
编辑 收藏
近日在学校bbs上与人讨论C++的typeid关键字的实现问题,有人提到type_info的地址是存放在虚表的第一个位置上,颇觉得不妥,于是我在vc2003下实验了一番
在vc下,使用typeid的时候,如果typeid施加给的类型是没有vptr的class或者根本不是class
那么汇编是
mov dword ptr [addr],offset A `RTTI Type Descriptor' (42AD40h)
也就是编译器生成一个简单的type_info对象的表,并且在编译期静态决定下标,做一个简单查表操作。
如果typeid的操作对象是具有vptr的class,但是并不是一个引用或者指针的解引用形式,例如
A a;
typeid(a);
那么仍然仅仅会做查表操作
如果typeid的操作对象是具有vptr的class,并且是引用或者指针的解引用形式,例如
A * p = new A;
A & r = * p;
typeid( * p);
typeid(r);
那么就会调用一个叫___RTtypeid的函数,并通过某种方法来获取type_info对象
下面是___RTtypeid的反汇编,这里只列出关键的几条指令
0041213E mov ecx,dword ptr [inptr] ;inptr是对象的地址
00412141 mov edx,dword ptr [ecx]
00412143 mov eax,dword ptr [edx - 4 ]
0041215F mov ecx,dword ptr [eax + 0Ch]
00412162 mov dword ptr [ebp - 48h],ecx
0041216C mov eax,dword ptr [ebp - 48h]
基本上等价于C语言的
int a1 = ( int )p; // p是对象的地址
int a2 = * ( int * )a1 - 4 ;
int a3 = * ( int * )a2 + 12 ;
int a4 = * ( int * )a3;
那么从这段代码可以看出vc下type_info对象的存放位置[如下图]
也就虚表下标为-1的位置上存放了一个指向一个未知的表的指针(暂且将此表命名为runtime_info_table)
runtime_info_table的第4格上存放了type_info对象的地址
至于runtime_info_table里前3格上存放的是什么, 还需要再研究研究
一般来说它们全是0, 但是对于多重虚继承的类, 第二格上会是4, 可能和指针的偏移量有关.
posted @
2006-10-26 10:46 shifan3 阅读(3330) |
评论 (5) |
编辑 收藏
Xpressive是一个C++的正则表达式库,目前是Boost的候选库。
Xpressive和Boost.Regex的区别很大。首先,Xpressive是一个纯头文件的库,也是说,在使用之前不需要预先编译。其次,Xpressive支持类似于Spirit的静态语义定义。
我们先来看一个例子:
#include <iostream>
#include <boost/xpressive/xpressive.hpp>
using namespace boost::xpressive;
int main()
{
std::string hello( "hello world!" );
sregex rex = sregex::compile( "(\\w+) (\\w+)!" );
smatch what;
if( regex_match( hello, what, rex ) )
{
std::cout << what[0] << '\n'; // whole match
std::cout << what[1] << '\n'; // first capture
std::cout << what[2] << '\n'; // second capture
}
return 0;
}
这是使用Xpressive动态语义定义的例子,其中sregex::compile函数编译一个表示正则文法的串,并返回一个正则对象sregex
使用regex_match来使用这个正则对象匹配一个串。结果储存在what内
其中what[0]返回整个串,what[1]~what[n]返回文法中用于标记的部分(用小括号括起来的部分)
最后将输出
hello world!
hello
world
如果想在一个串中查找符合该文法的子串,可以使用regex_search,用法和regex_match一样,此外还可以用regex_replace来进行替换。
静态文法:
Xpressive除了可以用compile来分析一个文法串之外,还可以用类似于Spirit的方式来静态的指定文法:
sregex re = '$' >> +_d >> '.' >> _d >> _d;
这将定义一个表示金额的串,其中_d表示一个数字,相当于串 $\d+.\d\d
这样定义文法将比之前的动态定义更加高效,并且还有一个附加的好处:
分级定义:
sregex re = '$' >> +_d >> '.' >> _d >> _d;
sregex s = '(' >> re >> ')';
这样s表示为用括号括起来的re
通过分级定义,文法能被表示的更加清楚。
更加棒的是,分级定义还可以向后引用,因此能够分析EBNF
sregex group, factor, term, expression;
group = '(' >> by_ref(expression) >> ')';
factor = +_d | group;
term = factor >> *(('*' >> factor) | ('/' >> factor));
expression = term >> *(('+' >> term) | ('-' >> term));
expression定义了一个四则表达式,注意其中group的定义。
这里必须使用by_ref是因为Xpressive默认是值拷贝,如果这里使用默认的方式,那么会造成一个无限循环。
Xpressive可以在这里下载
http://boost-consulting.com/vault/index.php?PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535&direction=0&order=&directory=Strings%20-%20Text%20Processing&PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535
内有详细的文档
posted @
2006-07-27 16:27 shifan3 阅读(3090) |
评论 (4) |
编辑 收藏
看了546@C++@Freecity之后,发觉非常有意思,由此产生一些想法
很多时候写一个类的时候,需要多个模版参数,例如一个遗传算法的算法类,需要一个模版参数来指定交配方式,另一个模版参数来指定子代选择的方式,还要一个参数来指定变异的方式。那么一般来说,这个类会写成:
template<class T //描述问题的一个类
, class CrossPolicy = AvgCrossPolicy //杂交方式
, class SelectPolicy = DefaultSelectPolicy //子代选择的方式
, class VariationPolicy = ReverseVariationPolicy> //变异方式
class Gene
: private AvgCrossPolicy
, private SelectPolicy
, private VariationPolicy
{
....
};
这样用户要使用该类的时候,可以直接指定T,就行了,然而如果要指定变异方式,那么就必须把所有的参数都显式的写出来,很不方便
546提供了一种有效的方法,可以让我们仅仅指定变异参数,而不用写出另两个Policy
甚至允许我们以任意的顺序书写几个Policy参数,都不会有问题
预备知识:
TypeList
一个TypeList是一个类型的容器
template <typename Type_, typename Next_>
struct TypeList
{
typedef Type_ Type;
typedef Next_ Next;
};
这就是一个TypeList。
看这个写法,是不是像一个链表?
首先定义一个类型来表示链表尾:class NullType{};
现在一个包含了2个类型的TypeList就可以写为:
TypeList<T1, TypeList<T2, NullType> >
如何在一个TypeList中查找一个类型的子类?
首先要有一个IsDerivedFrom<Base, T>
这个比较简单
template<class Base, class T>
class IsDerivedFrom
{
struct large{char a[2];};
static char pred(Base*);
static large pred(...);
public:
enum {Is = sizeof(pred((T*)0)) == sizeof(char)};
};
然后FindChild就容易了
template <class List, class Base>
struct FindChild
{
template <bool IsChild>
struct Select
{
typedef typename List::Type Type;
};
template <>
struct Select<false>
{
typedef typename FindChild<typename List::Next, Base>::Type Type;
};
typedef typename Select<IsDerivedFrom<Base, typename List::Type> >::Type Type;
};
当然还要对一些特殊情况进行特化,例如NullType
template <class Base>
struct FindChild<NullType, Base>
{
typedef NullType Type;
};
这里使用NullType来表明没找到
实际操作:
首先需要给3个Policy3个基类,分别叫
class AvgCrossPolicyBase{};
class SelectPolicyBase{};
class VariationPolicyBase{};
内容为空就行了,这样也没有虚函数调用的开销
然后声明一个类来表示默认情况:
class DefaultPolicy{};
定义一个宏
#define TYPELIST_3_N(a, b, c) TypeList<a, TypeList<b, TypeList<c, NullType> > >
下面要写一些选择器,用于把合适的类型选择出来,如果没找到,则要使用默认的类型
template <class List, class Base, class DefaultType>
struct Selector
{
template <class RetType>
struct Judge
{
typedef RetType Type;
};
template<>
struct Judge<NullType>
{
typedef DefaultType Type;
};
typedef typename Judge<typename FindChild<List, Base>::Type >::Type Type;
};
好啦,现在整个类的声明可以写为
template<class T
, class CrossPolicy_ = DefaultPolicy
, class SelectPolicy_ = DefaultPolicy
, class VariationPolicy_ = DefaultPolicy //其后的参数用户不可指定
, class List = TYPELIST_3_N(CrossPolicy_, SelectPolicy_, VariationPolicy_)
, class CrossPolicy = typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type
, class SelectPolicy = typename Selector<List, SelectPolicyBase, DefaultSelectPolicy>::Type
, class VariationPolicy = typename Selector<List, VariationPolicyBase, ReverseVariationPolicy>::Type
>
class Gene
: private CrossPolicy
, private SelectPolicy
, private VariationPolicy
{
....
};
其中第4-7个参数(List,CrossPolicy,SelectPolicy和VariationPolicy)是不由用户指定的,仅仅是为了起一个别名
第一个参数T必须指定,然后2,3,4这3个参数就可以任意的改变顺序了
例如,可以写Gene<T, DefaultSelectPolicy, AvgCrossPolicy>而不会有任何问题
如果不想要最后面几个参数的话也行,但是代码就要稍微长一点
而且最好在类里面进行3个typedef
typedef typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type CrossPolicy;
等,以便在实现的时候使用
posted @
2006-07-24 01:06 shifan3 阅读(991) |
评论 (9) |
编辑 收藏
摘要: 发信人: shifan (家没有豚豚 T.T), 板面: C++标 题: 如何实现Lambda[第二部分]发信站: 飘渺水云间 (Thu Jun 8 23:30:20 2006), 转信
章节:八:第一部分的小结九:简化,如何减少Lambda代码的冗余和依赖性十:bind的实现十一:实现phoenix
八. 中期总结目前的结果是这样的...
阅读全文
posted @
2006-07-15 15:32 shifan3 阅读(955) |
评论 (0) |
编辑 收藏
摘要: 一. 什么是Lambda所谓Lambda,简单的说就是快速的小函数生成。在C++中,STL的很多算法都要求使用者提供一个函数对象。例如for_each函数,会要求用户提供一个表明“行为”的函数对象。以vector<bool>为例,如果想使用for_each对其中的各元素全部赋值为true,一般需要这么一个函数对象,
c...
阅读全文
posted @
2006-06-09 13:23 shifan3 阅读(2956) |
评论 (7) |
编辑 收藏
最近为了解析SQL语法,怀着试一试的心态去翻了翻boost的spirit库,因为该库的文档的简介里写着LL parser framework represents parsers directly as EBNF grammars in inlined C++。看着framework这个词自然觉得这个库很牛B,试用了一下果然如此。
所谓EBNF即扩展巴克斯范式,是一种描述Context-Free Language的文法。在目前常见的非自然语言中,大部分都可以用EBNF表示。例如:
group ::='('exp ')'
factor ::=integer| group
term ::=factor(('*'factor)|('/'factor ))*
exp ::=term(('+'term)|('-'term ))*
这是一个整数表达式的EBNF。该段描述用spirit在C++中的实现则是:
rule<> group, factor, term, exp;
group = '(' >> exp >> ')';
factor = int_p | group;
term = factor >> *(('*' >> factor) | ('/' >> factor));
exp = term >> *(('+' >> term) | ('-' >> term));
这里使用=代替::=, 用>>代替空格连接。并且由于C++语法所限,EBNF中后置的*在spirit中改为前置。
等式左边的单词被称为一个rule,等式右边为rule的定义。我们可以看出一个group是一个exp加上一对括号,一个factor是一个整数或者一个group,一个term是一个或多个factor用*/连接,一个exp是一个或多个term用+-连接。处于最顶端的exp可以据此识别出以下表达式
12345
-12345
+12345
1 + 2
1 * 2
1/2 + 3/4
1 + 2 + 3 + 4
1 * 2 * 3 * 4
(1 + 2) * (3 + 4)
(-1 + 2) * (3 + -4)
1 + ((6 * 200) - 20) / 6
(1 + (2 + (3 + (4 + 5))))
得到一个rule之后,我们就可以用 parse函数对一个串进行识别了。例如
parse( " (1 + (2 + (3 + (4 + 5)))) " , exp);
该函数返回一个结构parse_info,可以通过访问其中的full成员来判断是否成功识别,也可以访问stop成员来获知失败的位置。这里要特别提一点,关于各个符号之间的空格,spirit的文档的正文说的是给parse再传一个参数space_p,通知parse跳过所有的空格,然而在FAQ中又提到,如果使用以上方法定义rule,第三个参数传space_p会失败。原因是使用rule默认定义的规则被称为character level parsing,即字符级别解析,而parse的第3个参数仅适用于phrase level parsing,即语法级别解析。要使用第3个参数可以有几种方法。
1。在parse的第二个参数直接传入一个EBNF表达式,不创建rule对象。
parse( " hello world " , * anychar_p, space_p);
2。以rule<phrase_scanner_t>创建rule。
rule < phrase_scanner_t > exp;
注意虽然可以用这两个办法屏蔽空格,但是这样可能完全改变EBNF文法的语义,尤其是在语言本身需要识别空格的时候。对于这种情况,可以不使用第三个参数,并在需要出现空格的地方加上space_p,或者+space_p及*space_p,其中+和*分别表示后面的符号连续出现一次以上和0次以上。例如一个以空格分隔的整数列表可以写成int_p >> *(+space_p >> int_p)
如上使用parse可以识别一个串,但并不能做更多的操作,例如将语法里的各个成分提取出来。对于这样的需求,可以通过actor实现。下面是使用actor的一个简单例子
bool
parse_numbers(char const* str, vector<double>& v)
{
return parse(str,
// Begin grammar
(
real_p[push_back_a(v)] >> *(',' >> real_p[push_back_a(v)])
)
,
// End grammar
space_p).full;
}
注意到real_p后面的[],中括号里面是一个仿函数(函数指针或者函数对象),该仿函数具有如下调用型别
void operator()(IterT first, IterT last) const;
void operator()(NumT val) const;
void operator()(CharT ch) const;
一旦spase发现了匹配real_p的子串,就会调用该functor。不同的rule可能会对应不同的调用型别。
第一个型别针对一般规则,first和last为两个指向字符的迭代器(一般为char*),匹配的子串为[first, last)
第二个型别针对数字型规则,如real_p和int_p, 参数val是一个数字类型。
第三个性别针对单字符型规则,如space_p, 参数ch是一个字符类型。
real_p[push_back_a(v)]中的push_back_a是一个spirit已经定义好的functor,它会将匹配好的内容依照匹配到的时间顺序调用v的push_back函数加入到v中。
到此spirit的常用功能就都介绍完了。要详细深入了解可以参考spirit的文档。
最后在题一个注意要点。spirit的各种EBNF连接都是指针连接,因此才能在expression被赋值前就在group的定义里面使用。所以在使用EBNF的时候一定要小心不要将局部变量的rule提供给全局或者类成员变量使用,例如:
class A
{
rule<> s;
A()
{
rule<> r = int_p | hex_p;
s = r >> *(+space_p >> r); //error, r destructed after return
}
};
如果真想使用局部作用域,可以在局部的rule前面加上static.
posted @
2005-12-18 12:02 shifan3 阅读(7079) |
评论 (5) |
编辑 收藏