免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: 没本
打印 上一主题 下一主题

C++字符串常量编译时转CRC32数值常量,有办法实现吗?(答案已经公开) [复制链接]

论坛徽章:
0
21 [报告]
发表于 2012-02-05 20:39 |只看该作者
回复 16# gtkmm


    尽管有这些限制,不过要是C++03对它都能支持的话,也是一种可用的方案。

论坛徽章:
0
22 [报告]
发表于 2012-02-05 20:57 |只看该作者
回复 17# OwnWaterloo


    我在考虑把这个和perfect hashing结合起来用在我的项目中。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
23 [报告]
发表于 2012-02-05 21:20 |只看该作者
回复 13# 没本

为了简单,我也只写个求和吧……

  1. constexpr int f(char const* p, int acc=0)
  2. { return *p? f(p+1, *p+acc): acc; }

  3. enum {
  4.       y0 = f("lc"),
  5.       y1 = 'l'+'c',
  6. };
  7. typedef int check[y0==y1? 1: -1];
复制代码
g++ -c -std=c++0x -Wall

g++4.6,木有编译错误

关于constexpr是否允许递归……  貌似在c++11讨论中有过争论,最终是否允许我也不知道……
如果不允许递归,那constexpr作用就很有限了。
如果允许递归,标量计算还是没问题的。

论坛徽章:
0
24 [报告]
发表于 2012-02-05 21:57 |只看该作者
回复 23# OwnWaterloo


    常量表达式函数由于不允许声明局部变量,一些需要中间结果的计算不方便拿递归来做。尽管有人提出可以用函数的参数列表中的变量来保存中间结果,但这么做在将来是否符合标准还很难说。求和用递归还是容易实现的。

论坛徽章:
0
25 [报告]
发表于 2012-02-05 23:22 |只看该作者
本帖最后由 AD8018 于 2012-02-06 15:37 编辑

这个是优化时计算,不叫编译时计算吧
不优化的情况下,反汇编出来看,计算过程全在代码里。

--------------------------------------------------

更正最新的学习结果,
http://en.wikipedia.org/wiki/C%2B%2B11
看了下constexpr, 的确是能保证编译时计算的


C++11 introduced the keyword constexpr, which allows the user to guarantee that a function or object constructor is a compile-time constant. The above example can be rewritten as follows:
constexpr int get_five() {return 5;}

int some_value[get_five() + 7]; // Create an array of 12 integers. Legal C++11
This allows the compiler to understand, and verify, that get_five is a compile-time constant.
The use of constexpr on a function imposes some limitations on what that function can do. First, the function must have a non-void return type. Second, the function body cannot declare variables or define new types. Third, the body may only contain declarations, null statements and a single return statement. There must exist argument values such that, after argument substitution, the expression in the return statement produces a constant expression.
Prior to C++11, the values of variables could only be used in constant expressions if the variables are declared const, have an initializer which is a constant expression, and are of integral or enumeration type. C++11 removes the restriction that the variables must be of integral or enumeration type if they are defined with the constexpr keyword:
constexpr double acceleration_due_to_gravity = 9.8;
constexpr double moon_gravity = acceleration_due_to_gravity / 6.0;
Such data variables are implicitly const, and must have an initializer which must be a constant expression.
In order to construct constant expression data values from user-defined types, constructors can also be declared with constexpr. A constexpr constructor's function body can only contain declarations and null statements, and cannot declare variables or define types, as with a constexpr function. There must exist argument values such that, after argument substitution, it initializes the class's members with constant expressions. The destructors for such types must be trivial.
The copy constructor for a type with any constexpr constructors should usually also be defined as a constexpr constructor, in order to allow them to be returned by value from a constexpr function. Any member function of a class, such as copy constructors, operator overloads, etc., can be declared as constexpr, so long as they meet the requirements for constexpr functions. This allows the compiler to copy classes at compile time, perform operations on them, etc.
If a constexpr function or constructor is called with arguments which aren't constant expressions, the call behaves as if the function were not constexpr, and the resulting value is not a constant expression. Likewise, if the expression in the return statement of a constexpr function does not evaluate to a constant expression for a particular invocation, the result is not a constant expression.

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
26 [报告]
发表于 2012-02-06 08:53 |只看该作者
本帖最后由 starwing83 于 2012-02-06 09:58 编辑
没本 发表于 2012-02-05 21:57
回复 23# OwnWaterloo


函数式编程本来就没有局部变量哈哈哈哈~~我爱constexpr……

刚刚试了一下,gcc里面的constexpr是可以递归的:
static constexpr int crc32tabi_ce(uint32_t c, int k = 0) {
    return k == 8 ? c : crc32tabi_ce(((c & 1) ? (0xedb88320L ^ (c >> 1)) : (c >> 1)), k + 1);
}
不过gcc设置了递归深度,最多522似乎,不知道标准是不是允许递归。

论坛徽章:
0
27 [报告]
发表于 2012-02-06 12:55 |只看该作者
我是来看各位的代码的。

论坛徽章:
0
28 [报告]
发表于 2012-02-06 19:41 |只看该作者
回复 26# starwing83


    是吗,我不会函数式编程,外行了。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
29 [报告]
发表于 2012-02-07 22:43 |只看该作者
没本 发表于 2012-02-06 19:41
回复 26# starwing83
是吗,我不会函数式编程,外行了。


C++模板元编程,比如你在1楼的代码,就是函数式编程,而且是纯函数式。

没本 发表于 2012-02-05 21:57
回复 23# OwnWaterloo
常量表达式函数由于不允许声明局部变量,一些需要中间结果的计算不方便拿递归来做。尽管有人提出可以用函数的参数列表中的变量来保存中间结果,但这么做在将来是否符合标准还很难说。求和用递归还是容易实现的。


用递归容易实现的不仅仅是求和。
上面也说了,C++模板元编程是纯函数式。没有变量可以用,没有for,while,do while什么的可以用。
当感到需要它们的时候,全都可以改写为递归的形式(并且是尾递归),两者是等价的。

其他的一些变换,比如有副作用的表达式 x = x+1 or x = x++ 什么的,可以改写为新的局部变量 int new_x = x+1。
比如局部变量: { int y = x; 使用y的代码 }
可以改写为: [](int y){ 使用y的代码 }(x)

没本 发表于 2012-02-05 18:55
回复 9# OwnWaterloo
constexpr做常量表达式函数时,限制颇多,目前不借助模板还做不到吧。


从上面可以看出两者是很类似的。下面是仅仅使用constexpr在编译时求crc32(1楼代码机械翻译为纯函数式……)

  1. constexpr unsigned lookup(unsigned c, unsigned k=8)
  2. { return k==0? c: lookup(c&1? 0xedb88320 ^ (c>>1): c>>1, k-1); }

  3. constexpr unsigned crc32(char const* p, unsigned sum = 0x4c11db7)
  4. { return *p==0? sum: crc32(p+1, lookup((sum>>24) ^ *p) ^ (sum<<8) ); }

  5. typedef int check[crc32("This is a string")==0xd577deda
  6.                   && crc32("This is another string")==0xdd55a5b6
  7.                   ? 1:-1];
复制代码
区别是仅仅使用constexpr就只能操作标量,没法对array之类的东西编程,没法产生那个table……
但这样实现的crc32是一个普通的函数:
1. 如果接受的参数是一个constexpr,输出的参数也是constexpr
2. 也可以接受运行时参数(template-based的就不行,完全是编译时的东西)。


最后,关于constexpr是否允许递归: http://www.open-std.org/jtc1/sc2 ... ers/2009/n2826.html
没仔细看,但有一些信息很关键:
1. 最后的附录里增加了一个实现要求 —— Recursive constexpr function invocations [512].
gcc有一个对应的参数-fconstexpr-depth=
2. 这是在暗示某个时刻C++0x的草稿从不允许改为允许, 如果最终又再改回不允许那也太搓了……

我感觉不会禁止的。即使函数式编程在c++中不是主流,但只要了解模板元编程就能体会递归在纯函数式中的地位。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP