Enums, Macros, Unicode and Token-Pasting

来源:互联网 发布:辐射4帅哥捏脸数据 编辑:程序博客网 时间:2024/05/16 17:58

Enums, Macros, Unicode and Token-Pasting

文章原作者是Rocky,来自Visual C++ IDE team。
译者是偶,liveck@antiy.net 原文出自这里:VC team Blog

下面我想讨论的是C++中利用宏生成枚举类型的技巧。 最近我用这个技巧来区分C++中的不同类型,例如类、变量和函。 把类型列表放到一个文件中会为增加新类型和使用多个类型带来方便。以下的例子取自我工作中的代码。 我见到这个技巧在许多其他的场合中都被用到,但是却不曾在教课书中提及——所以值得在这里我们要讨论一下。

考虑下面的枚举类型:

enum Animal { dog, cat, fish, bird };

现在dog在0的位置。 编译器本身是强类型安全的,但是宏却不是。对于枚举类型,VS的调试器会显示出具体的类型而不是一个个整数长了。那么用于输出枚举常量的函数需要一个更人性的格式转换。下面的代码或许有帮助:

wchar_t* AnimalDiscription[] = { L"dog", L"cat", L"fish", L"bird" };

有了这个数组,在调试的时候就能够输出友好的字符串了,而我们所需要的只是根据枚举量查找数组下标。

使用宏自动生成枚举类型我就只需要维护一份实体,这里不仅仅是说枚举常量还包括对应的字符串。 考虑文件animal.inc:

MYENUM(dog)

MYENUM(cat)

MYENUM(fish)

MYENUM(bird)

和对应的C++ 代码:

enum Animal {

#define MYENUM(e) _##e,

#include "animal.inc"

#undef MYENUM

};

wchar_t* AnimalDescription[] = {

#define MYENUM(e) L"_" L#e,

#include "animal.inc"

#undef MYENUM

};

现在只要编辑animal.inc就能同时更新枚举类型和对应的描述。 我在常量前面加了下划线以使宏工作正常。这是因为token-pasting操作符##不能出现在宏首。通过#我们可以产生字符串。在#前面加一个L可以将字符串声明为宽字符。

这些宏可以通过编译器的参数/P和/EP来调试。编译器会产生如下的预处理文件:

enum Animal {

_dog,

_cat,

_fish,

_bird,

};

wchar_t* AnimalDescription[] = {

L"_" L"dog",

L"_" L"cat",

L"_" L"fish",

L"_" L"bird",

};

宏字符串替换技巧也可以用于产生代码。下面是一个用字符串替换产生函数原型的例子:

#define MYENUM(e) void Order_##e();

#include "animal.inc"

#undef MYENUM

This expands to:

void Order_dog();

void Order_cat();

void Order_fish();

void Order_bird();

你可能会想根据动物的种类做一些事情。下面有一个switch的例子:

#define MYENUM(e) case _##e:/

Order_##e();/

break;

#include "animal.inc"

#undef MYENUM

This expands to:

case _dog: Order_dog(); break;

case _cat: Order_cat(); break;

case _fish: Order_fish(); break;

case _bird: Order_bird(); break;

在这个例子里面还需要给每一个函数写个定义包括 Order_dog()、Order_cat()、等等。如果你给animal.inc加了一种新的动物,记得要写个新的Order_开头的函数的定义。不过,链接器报错会提醒你这个事情的。

宏字符串替换是一个非常好用的工具, 特别是可以将内部数据集中保存,大幅度的减少出错的机会。

==============================================

翻译过来给新人看,C++中有许多非常技巧的东西,有人说C++是一门为技巧而生的语言。不过重要的不是技巧,而是思想,不是么?

原创粉丝点击