返回   cpper编程论坛 > C/CPP/TMP/GP
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

回复
 
LinkBack 主题工具 显示模式
  #1 (permalink)  
旧 2008-01-30
Dd 的头像
Dd Dd 当前离线
普通会员
 
注册日期: 2002-10-16
住址: 上海
帖子: 49
Dd 正向着好的方向发展
发送 MSN 消息给 Dd
灯泡 基于模板参数类型的“字面常量选择”

标题有点拗口,实际上意思很简单。例如:

代码:
template<typename TChar> class C { public: void foo(TChar ch) { switch( ch ) { case 'A': ...; case 'B': ...; case 'C': ...; } } };
如果TChar是char,那么一切没问题。但如果TChar是wchat_t,那么我必须要将其中的switch改成:

代码:
switch( ch ) { case L'A': ...; case L'B': ...; case L'C': ...; }
现在问题就是,我不希望将这段复制两份(仅为了加上这些L),各位有何高见?关于“宏”的解决方法,也是可接受的…………
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #2 (permalink)  
旧 2008-01-30
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

把成员函数foo偏特化一下就行了
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #3 (permalink)  
旧 2008-01-31
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

代码:
foo(TCHAR c) { switch(c) { case _T('A'): case _T('B'): case _T('C'): } }
_T vc直接提供
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #4 (permalink)  
旧 2008-01-31
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

使用_T的宏

vc上自己有

foo(TCHAR c)
{
switch
{
case _T('A'):
}
}
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #5 (permalink)  
旧 2008-02-01
Dd 的头像
Dd Dd 当前离线
普通会员
 
注册日期: 2002-10-16
住址: 上海
帖子: 49
Dd 正向着好的方向发展
发送 MSN 消息给 Dd
默认 回复: 基于模板参数类型的“字面常量选择”

引用:
作者: bankrock 查看帖子
把成员函数foo偏特化一下就行了
当然,这是可以的(就像把代码复制一遍一样……)。但问题是,如果switch-case中的“...”是很大、很复杂的一些代码呢?在这个问题上,偏特化和复制代码效果差不多。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #6 (permalink)  
旧 2008-02-01
Dd 的头像
Dd Dd 当前离线
普通会员
 
注册日期: 2002-10-16
住址: 上海
帖子: 49
Dd 正向着好的方向发展
发送 MSN 消息给 Dd
默认 回复: 基于模板参数类型的“字面常量选择”

引用:
作者: SpitFire 查看帖子
代码:
foo(TCHAR c) { switch(c) { case _T('A'): case _T('B'): case _T('C'): } }
_T vc直接提供
您似乎还没有看明白我的问题。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #7 (permalink)  
旧 2008-02-02
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,764
Elminster 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

引用:
作者: Dd 查看帖子
当然,这是可以的(就像把代码复制一遍一样……)。但问题是,如果switch-case中的“...”是很大、很复杂的一些代码呢?在这个问题上,偏特化和复制代码效果差不多。
这个应该就是 traits 的典型场景吧:

代码:
template<typename TChar, char C, wchar_t UC> struct selector; template<char C, wchar_t UC> struct selector<char, C, UC> { static const char result = C; }; template<char C, wchar_t UC> struct selector<wchar_t, C, UC> { static const wchar_t result = UC; }; ... switch (TChar c) { case selector<TChar, 'C', L'C'>::result : ... break; ... }
然后定义一个宏把那一串变成 S('C') 就好了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #8 (permalink)  
旧 2008-02-02
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

那这样加个辅助模版类集合:
代码:
template <class TChar> class Alphabet {}; class Alphabet<char> { public: enum {A = 'A', B = 'B', ......}; }; class Alphabet<wchar_t> { public: enum {A = L'A', B = L'B', .... }; }; template<typename TChar> class C { public: void foo(TChar ch) { switch( ch ) { case Alphabet<TChar>::A: ...; case Alphabet<TChar>::B: ...; case Alphabet<TChar>::C: ...; } } };
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #9 (permalink)  
旧 2008-02-03
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

我认为_TEXT宏不是正解。因为如下代码编译错误:

代码:
#include <iostream> template<typename TChar> void foo(TChar ch){ switch(ch){ case 'C': case L'C': std::cout<<"C branch\n"; break; case 'A': case L'A': std::cout<<"A branch\n"; break; default: std::cout<<"default branch\n"; break; } } int main(int, char**){ wchar_t wc=L'A'; char c='C'; foo(wc); foo(c); }
错误信息是:
test2.cpp:7: error: duplicate case value
test2.cpp:6: error: previously used here

再查看_TEXT宏的定义。
代码:
#ifdef USE_WCHAR #define TEXT(s) L##s #define _T(s) L##s #else #define TEXT(s) s #define _T(s) s #endif
所以_TEXT无法得到正确结果,必须用前面回复的模板类参数选择方法。代码和运行结果如下:

代码:
#include <iostream> template<typename TChar, char c, wchar_t wc>struct LitChar{ const static char result=c;//default }; template<char c, wchar_t wc>struct LitChar<wchar_t, c, wc>{ const static wchar_t result=wc; }; template<typename TChar> void foo(TChar ch){ switch(ch){ case LitChar<TChar, 'C', L'C'>::result: std::cout<<"C branch\n"; break; case LitChar<TChar, 'A', L'A'>::result: std::cout<<"A branch\n"; break; default: std::cout<<"default branch\n"; break; } } int main(int, char**){ wchar_t wc=L'A'; char c='C'; foo(wc); foo(c); }
结果是:
A branch
C branch
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #10 (permalink)  
旧 2008-02-03
Dd 的头像
Dd Dd 当前离线
普通会员
 
注册日期: 2002-10-16
住址: 上海
帖子: 49
Dd 正向着好的方向发展
发送 MSN 消息给 Dd
默认 回复: 基于模板参数类型的“字面常量选择”

Elminster:正解!和我现在的做法基本一致,就连名字(selector)都很像

bankrock:可行,但会丢失类型信息。

liuxinyu:谢谢回答。

那么,现在解决了char/wchar_t字面常量问题,那么再加大点难度吧。同样的问题如何处理“字面常量字符串”呢?例如,对于以下代码中的“字面字符串”:

代码:
characterData(void *userData, const XML_Char *s, int len) { FILE *fp = (FILE *)userData; for (; len > 0; --len, ++s) { switch (*s) { case T('&'): fputts(T("&amp;"), fp); break; case T('<'): fputts(T("&lt;"), fp); break; case T('>'): fputts(T("&gt;"), fp); break; #ifdef W3C14N case 13: fputts(T("&#xD;"), fp); break; #else case T('"'): fputts(T("&quot;"), fp); break; case 9: case 10: case 13: ftprintf(fp, T("&#%d;"), *s); break; #endif default: puttc(*s, fp); break; } } }
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #11 (permalink)  
旧 2008-02-03
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

我觉得没必要弄这么复杂,要么你的程序是unicode的,要么不是,一个程序要同时有char跟wchat_t而且是业务代码是没太大必要,而且使用template就肯定要使用源文件发布

代码:
void foo(TCHAR c) { switch(c) { case _T('A'): break; case _T('C'): break; case _T('D'): break; } } int main() { foo(_T('A')); }
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #12 (permalink)  
旧 2008-02-03
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

不明白你后面那个问题,为什么要使用字面字符串

做成通用可配置不好么,字面量是编译期
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #13 (permalink)  
旧 2008-02-08
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

感觉应该先确认所处理文件的编码是否unicode
这段代码基本是C风格的,有点传统parser的状态机感觉。

还有,如果退一步真的需要动态比较一个字符串是否和某串相等。比较推荐的做法如下:
从文件中读取字符出来,转换成unicode附加到当前串尾,然后交给状态机处理。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #14 (permalink)  
旧 2008-02-15
liuxinyu 的头像
高级会员
 
注册日期: 2006-02-09
帖子: 311
文章: 49
liuxinyu 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

我给一个偏向unicode的解法,思路如下,在比较字符常量时,统一转换成wchar_t后在比较。在处理字符串常量时,如无特殊情况,一律输出unicode。所有的转换不需手工显示进行。利用模板推到分派。
代码:
#include <iostream> template<typename T, wchar_t x> struct EqualChar; template<wchar_t x> struct EqualChar<wchar_t, x>{ static bool isEqual(wchar_t y){return x==y;} }; template<wchar_t x> struct EqualChar<char, x>{ static bool isEqual(char y){return x==std::cin.widen(y);} }; template<typename T> struct LiteralString; template<> struct LiteralString<char>{ static void print(const wchar_t* wstr){ while(*wstr) std::cout<<std::cin.narrow(*wstr++, '*'); } }; template<> struct LiteralString<wchar_t>{ static void print(const wchar_t* wstr){ std::cout<<wstr; } }; template<typename T> void testChar(T x){ if(EqualChar<T, L'A'>::isEqual(x)) std::cout<<"input char equal to A\n"; } template<typename T> void foo(const T* str){ while(*str){ if(EqualChar<T, L'&'>::isEqual(*str)) LiteralString<T>::print(L"amp;"); else if(EqualChar<T, L'<'>::isEqual(*str)) LiteralString<T>::print(L"lt;"); else if(EqualChar<T, L'>'>::isEqual(*str)) LiteralString<T>::print(L"gt;"); else std::cout<<*str; ++str; } std::cout<<'\n'; } int main(int, char**){ char c='A'; wchar_t wc='A'; testChar(c); testChar(wc); const char* str="<html>&foo</html>"; const wchar_t* wstr=L"<html>&foo;</html>"; foo(str); foo(wstr); }
程序输出:
代码:
C:\Users\chen\temp>g++ foo.cpp -o foo.exe C:\Users\chen\temp>foo input char equal to A input char equal to A lt;htmlgt;amp;foolt;/htmlgt; 0x44005c1041161091080x4400640x440052102111111590x44005c471041161091080x440064
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #15 (permalink)  
旧 2008-02-15
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,563
文章: 6
cat 正向着好的方向发展
默认 回复: 基于模板参数类型的“字面常量选择”

纯UNICODE好~ 在file读入的时候直接读成WCHAR直接在这个层次解决问题就是了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #16 (permalink)  
旧 2008-02-26
Dd 的头像
Dd Dd 当前离线
普通会员
 
注册日期: 2002-10-16
住址: 上海
帖子: 49
Dd 正向着好的方向发展
发送 MSN 消息给 Dd
默认 回复: 基于模板参数类型的“字面常量选择”

引用:
作者: Dd 查看帖子
Elminster:正解!和我现在的做法基本一致,就连名字(selector)都很像

那么,现在解决了char/wchar_t字面常量问题,那么再加大点难度吧。同样的问题如何处理“字面常量字符串”呢?例如,对于以下代码中的“字面字符串”:

代码:
characterData(void *userData, const XML_Char *s, int len) {...}

关于字符串常量的选择,我至今没有想到啥好办法。不过关于“字符选择”我做了一个简单的类,或许对其他人也有帮助:

代码:
// // CAsciiCharacters // /* [dev] * http://tongj.bokee.com/1649370.html */ #define __M_BASE_ASCII_Definition( TChar, prefix ) \ static const TChar \ NUL = prefix##'\0', /* Null char */ \ /* 001 SOH(Start of Header) */ \ /* 002 STX(Start of Text) */ \ /* 003 ETX(End of Text) */ \ /* 004 EOT(End of Transmission) */ \ /* 005 ENQ(Enquiry) */ \ /* 006 ACK(Acknowledgment) */ \ BEL = prefix##'\a', /* Bell */ \ BS = prefix##'\b', /* Backspace */ \ HT = prefix##'\t', /* Horizontal tab */ \ LF = prefix##'\n', /* Line feed */ \ VT = prefix##'\v', /* Vertical tab */ \ FF = prefix##'\f', /* Form feed */ \ CR = prefix##'\r', /* Carriage return */ \ /* 014 SO(Shift Out) */ \ /* 015 SI(Shift In) */ \ /* 016 DLE(Data Link Escape) */ \ /* 017 DC1(XON)(Device Control 1) */ \ /* 018 DC2(Device Control 2) */ \ /* 019 DC3(XOFF)(Device Control 3) */ \ /* 020 DC4(Device Control 4) */ \ /* 021 NAK(Negative Acknowledgement) */ \ /* 022 SYN(Synchronous Idle) */ \ /* 023 ETB(End of Trans. Block) */ \ /* 024 CAN(Cancel) */ \ /* 025 EM(End of Medium) */ \ /* 026 SUB(Substitute) */ \ /* 027 ESC(Escape) */ \ /* 028 FS(File Separator) */ \ /* 029 GS(Group Separator) */ \ /* 030 RS(Request to Send)(Record Separator) */ \ /* 031 US(Unit Separator) */ \ space = prefix##' ', \ exclamation_mark = prefix##'!', \ double_quote = prefix##'\"', \ number_sign = prefix##'#', \ dollar_sign = prefix##'$', \ percent = prefix##'%', \ ampersand = prefix##'&', \ single_quote = prefix##'\'', \ left_parenthesis = prefix##'(', \ right_parenthesis = prefix##')', \ asterisk = prefix##'*', \ plus = prefix##'+', \ comma = prefix##',', \ minus = prefix##'-', \ dot = prefix##'.', \ forward_slash = prefix##'/', \ num_0 = prefix##'0', \ num_1 = prefix##'1', \ num_2 = prefix##'2', \ num_3 = prefix##'3', \ num_4 = prefix##'4', \ num_5 = prefix##'5', \ num_6 = prefix##'6', \ num_7 = prefix##'7', \ num_8 = prefix##'8', \ num_9 = prefix##'9', \ colon = prefix##':', \ semi_colon = prefix##';', \ less_than = prefix##'<', \ equal_sign = prefix##'=', \ greater_than = prefix##'>', \ question_mark = prefix##'?', \ at_symbol = prefix##'@', \ letter_A = prefix##'A', \ letter_B = prefix##'B', \ letter_C = prefix##'C', \ letter_D = prefix##'D', \ letter_E = prefix##'E', \ letter_F = prefix##'F', \ letter_G = prefix##'G', \ letter_H = prefix##'H', \ letter_I = prefix##'I', \ letter_J = prefix##'J', \ letter_K = prefix##'K', \ letter_L = prefix##'L', \ letter_M = prefix##'M', \ letter_N = prefix##'N', \ letter_O = prefix##'O', \ letter_P = prefix##'P', \ letter_Q = prefix##'Q', \ letter_R = prefix##'R', \ letter_S = prefix##'S', \ letter_T = prefix##'T', \ letter_U = prefix##'U', \ letter_V = prefix##'V', \ letter_W = prefix##'W', \ letter_X = prefix##'X', \ letter_Y = prefix##'Y', \ letter_Z = prefix##'Z', \ left_bracket = prefix##'[', \ back_slash = prefix##'\\', \ right_bracket = prefix##']', \ caret = prefix##'^', \ underscore = prefix##'_', \ interpunct = prefix##'`', \ letter_a = prefix##'a', \ letter_b = prefix##'b', \ letter_c = prefix##'c', \ letter_d = prefix##'d', \ letter_e = prefix##'e', \ letter_f = prefix##'f', \ letter_g = prefix##'g', \ letter_h = prefix##'h', \ letter_i = prefix##'i', \ letter_j = prefix##'j', \ letter_k = prefix##'k', \ letter_l = prefix##'l', \ letter_m = prefix##'m', \ letter_n = prefix##'n', \ letter_o = prefix##'o', \ letter_p = prefix##'p', \ letter_q = prefix##'q', \ letter_r = prefix##'r', \ letter_s = prefix##'s', \ letter_t = prefix##'t', \ letter_u = prefix##'u', \ letter_v = prefix##'v', \ letter_w = prefix##'w', \ letter_x = prefix##'x', \ letter_y = prefix##'y', \ letter_z = prefix##'z', \ left_brace = prefix##'{', \ vertical_bar = prefix##'|', \ right_brace = prefix##'}', \ tilde = prefix##'~'; \ /* 127 DEL(delete) */ template<typename T> class CAsciiCharacters {}; template<> class CAsciiCharacters<char> { public: __M_BASE_ASCII_Definition( char, (char) ) }; template<> class CAsciiCharacters<wchar_t> { public: __M_BASE_ASCII_Definition( wchar_t, L ) };
例如用法:

代码:
template<typename TChar> class CBasicTextWriter { static const TChar s_chDelimiter = CAsciiCharacters<TChar>::space; }
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
回复

书签

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛启用 表情符号
论坛启用 [IMG] 代码
论坛禁用 HTML 代码
Trackbacks are 启用
Pingbacks are 启用
Refbacks are 启用



所有时间均为格林尼治时间 +9。现在的时间是 10:57 AM


Powered by vBulletin® 版本 3.7.0
版权所有 ©2000 - 2009,Jelsoft Enterprises Ltd.
(C) Copy Right All Right Reserved 2001 - 2007

Search Engine Friendly URLs by vBSEO 3.1.0