博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CppWeekly 08 constexpr
阅读量:2134 次
发布时间:2019-04-30

本文共 4846 字,大约阅读时间需要 16 分钟。

这个系列是从开始的,主要是复现Jason Turner的“C++ Weekly With Jason Turner”视频中的代码。

041 constexpr

Jason 在这期和后面几期讨论了constexpr的一些用法,非常有意思。把部分简单的运算从运行时移动到了编译时,可以提高运行效率。但是我还没有真正找到必须要这样做的的实际样例,主要是我写的代码,瓶颈都不在这种地方(瓶颈多了去了, 呵呵)。

C++17 中constexpr可以使用std::array和lambda函数了。这里搬运Jason的代码,并做了一丁点简单调整,如下所示。代码中生成了一个std::array,里面保存有16种颜色配置,需要生成一个新的array,内保存了上述16种颜色按照luma(可理解为亮度)从小到大排序的结果。所有运算均在编译时完成。

这是一个很好的例子解释了我们在编写c++代码时,我们是在设法和compiler沟通。compiler能做什么,做了什么,我们基本说的不算的,呵呵。

#include 
#include
#include
#include
struct Color {
std::uint8_t num; std::uint8_t r; std::uint8_t g; std::uint8_t b; double luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; };template < typename Colors >constexpr auto nearest_color( const Colors& colors, const std::uint8_t r, const std::uint8_t g, const std::uint8_t b ) {
return *std::min_element( begin(colors), end(colors), [r, g, b](const auto& lhs, const auto& rhs){
const auto square = [](const auto& t){
return t*t; }; return ( square( lhs.r - r ) + square( lhs.g - g ) + square( lhs.b - b ) ) < ( square( rhs.r - r ) + square( rhs.g - g ) + square( rhs.b - b ) ); } ); }template < std::size_t N >constexpr auto sort_by_luma( const std::array< Color, N >& colors ) {
auto retVal = colors; const auto arrayHead = &std::get<0>(retVal); const auto end = arrayHead + colors.size(); for ( std::size_t i = 0; i < colors.size(); ++i ) {
const auto begin = arrayHead + i; auto minElem = std::min_element( begin, end, [](const auto& lhs, const auto& rhs){
return lhs.luma < rhs.luma; } ); const auto tmp = *minElem; *minElem = *begin; *begin = tmp; } return retVal;}int main() {
constexpr std::array< Color, 16 > colors {
{
Color{
0, 0x00, 0x00, 0x00}, Color{
1, 0xFF, 0xFF, 0xFF}, Color{
2, 0x88, 0x39, 0x32}, Color{
3, 0x67, 0xB6, 0xBD}, Color{
4, 0x8B, 0x3F, 0x96}, Color{
5, 0x55, 0xA0, 0x49}, Color{
6, 0x40, 0x31, 0x8D}, Color{
7, 0xBF, 0xCE, 0x72}, Color{
8, 0x8B, 0x54, 0x29}, Color{
9, 0x57, 0x42, 0x00}, Color{
10, 0xB8, 0x69, 0x62}, Color{
11, 0x50, 0x50, 0x50}, Color{
12, 0x78, 0x78, 0x78}, Color{
13, 0x94, 0xE0, 0x89}, Color{
14, 0x78, 0x69, 0xC4}, Color{
15, 0x9F, 0x9F, 0x9F} }}; static_assert( 12 == nearest_color( colors, 128, 128, 128 ).num ); static_assert( 0 == nearest_color( colors, 0, 0, 0 ).num ); constexpr auto sorted_colors = sort_by_luma( colors ); static_assert(sorted_colors[ 0].num == 0); static_assert(sorted_colors[ 7].num == 14); static_assert(sorted_colors[ 8].num == 12); static_assert(sorted_colors[15].num == 1); for( const auto& c : sorted_colors ) {
std::cout << static_cast
(c.num) << ": " << c.luma << '\n'; } return sorted_colors[15].num;}

若运行这段代码,终端输出的是sorted_colors的内容,

0: 06: 58.83149: 65.69942: 73.2911: 804: 85.4398: 92.588414: 114.75912: 12010: 121.295: 137.77415: 1593: 165.717: 196.16913: 201.5611: 255

在complier explorer上,去掉所有和std::cout相关的代码,编译优化为-O3时,得到的汇编非常简单,就直接是一条mov加一条ret,就完事了,真神奇!见。

汇编代码

044 constexpr random number generator

我们甚至可以使用constexpr在编译时生成随机数!先不要管这个是用来作什么的,但是听上去很酷。

#include 
#include
constexpr auto seed() {
std::uint64_t shifted = 0; for ( const auto c : __TIME__ ) {
shifted <<= 8; shifted |= c; } return shifted;}struct PCG {
struct pcg_32_random_t {
std::uint64_t state = 0; std::uint64_t inc = seed(); }; pcg_32_random_t rng; typedef std::uint32_t ResultType_T; constexpr ResultType_T operator()() {
return pcg_32_random_r(); } static ResultType_T constexpr min() {
return std::numeric_limits
::min(); } static ResultType_T constexpr max() {
return std::numeric_limits
::max(); }private: constexpr ResultType_T pcg_32_random_r() {
std::uint64_t oldState = rng.state; rng.state = oldState * 6364136223846793005ULL + ( rng.inc|1 ); std::uint32_t xorshifted = ((oldState >> 18u) ^ oldState) >> 27u; std::uint32_t rot = oldState >> 59u; return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); }};constexpr auto get_random(int x) {
PCG pcg; while ( x > 0 ) {
pcg(); --x; } return pcg();}int main() {
constexpr auto r = get_random(10); return r;}

上述代码每次编译,main()的返回值都是一个随机的常量(基本随机,seed是通过时间生成的)。但是我在complier explorer上测试时,感觉并seed不一定是随时间变化的。但是在本地通过objdump -d命令输出汇编显示,每次编译出的随机数都是不同的。神奇!

转载地址:http://jiugf.baihongyu.com/

你可能感兴趣的文章
【Pyton】【小甲鱼】异常处理:你不可能总是对的
查看>>
APP性能测试工具
查看>>
【Pyton】【小甲鱼】类和对象
查看>>
压力测试工具JMeter入门教程
查看>>
作为一名软件测试工程师,需要具备哪些能力
查看>>
【Pyton】【小甲鱼】类和对象:一些相关的BIF(内置函数)
查看>>
【Pyton】【小甲鱼】魔法方法
查看>>
单元测试需要具备的技能和4大阶段的学习
查看>>
【Loadrunner】【浙江移动项目手写代码】代码备份
查看>>
Python几种并发实现方案的性能比较
查看>>
[Jmeter]jmeter之脚本录制与回放,优化(windows下的jmeter)
查看>>
Jmeter之正则
查看>>
【JMeter】1.9上考试jmeter测试调试
查看>>
【虫师】【selenium】参数化
查看>>
【Python练习】文件引用用户名密码登录系统
查看>>
学习网站汇总
查看>>
【Python】用Python打开csv和xml文件
查看>>
【Loadrunner】性能测试报告实战
查看>>
【自动化测试】自动化测试需要了解的的一些事情。
查看>>
【selenium】selenium ide的安装过程
查看>>