hrefspace

 找回密码
 立即注册
搜索
热搜: PHP PS 程序设计
查看: 1315|回复: 9

如何优雅地获取常量数列中某个值?

[复制链接]

585

主题

769

帖子

2007

积分

大司空

Rank: 5Rank: 5

积分
2007
发表于 2024-4-7 03:54:29 | 显示全部楼层 |阅读模式
问题是这样:

想获取 \(6\sigma\) 中的某一个值,在 C++11 之前是这么做的:
  1. #define _1_SIGMA_                   0.3085375#define _2_SIGMA_                   0.6914625#define _3_SIGMA_                   0.9331928#define _4_SIGMA_                   0.9937903#define _5_SIGMA_                   0.9997674#define _6_SIGMA_                   0.9999966#define SIGMA( n )                  ( _##n##_SIGMA_ )
复制代码

而如今,采用 C++17 标准后,我们可以这么写了:
  1. inline constexpr double SIGMA( std::size_t n ) noexcept{    constexpr double sigma[]{ 0.0, 0.3085375, 0.6914625, 0.9331928, 0.9937903, 0.9997674, 0.9999966 };    return sigma[ n ];}
复制代码

其实上面那个数组 sigma 是没有必要的(甚至无需给它命名),可以改写成如下:
  1. inline constexpr auto SIGMA( std::size_t n ) noexcept{    using D7 = double[ 7 ];    return D7{ 0.0, 0.3085375, 0.6914625, 0.9331928, 0.9937903, 0.9997674, 0.9999966 }[ n ];}
复制代码

以上皆能编译通过。



但是,我觉得仍不够“优雅”,觉得理想的代码应该是下面的:
  1. inline constexpr auto SIGMA( std::size_t n ) noexcept{    return { 0.0, 0.3085375, 0.6914625, 0.9331928, 0.9937903, 0.9997674, 0.9999966 }[ n ];}
复制代码
不过,很可惜,无 法 通 过 编 译 !



如果是你,用 C++ 会如何实现它?并尽可能保持优雅。。。
回复

使用道具 举报

0

主题

171

帖子

17

积分

新手上路

Rank: 1

积分
17
发表于 2024-4-7 03:55:27 | 显示全部楼层
刚刚同事给出一个方案,还算比较“优雅”:
  1. inline constexpr auto SIGMA( std::size_t n ) noexcept{    return std::begin( { 0.0, 0.3085375, 0.6914625, 0.9331928, 0.9937903, 0.9997674, 0.9999966 } )[ n ];}
复制代码
能够编译通过。

用到了 std::initializer_list 的非成员函数 std::begin(std::initializer_list)

如果项目中尚未 include 任何类型的标准库容器,请在文件前加上“#include <initializer_list>”
回复

使用道具 举报

0

主题

171

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2024-4-7 03:55:50 | 显示全部楼层
我或许会用const float SIGMA[]={...};,或许不优雅,哈哈。
回复

使用道具 举报

0

主题

171

帖子

36

积分

新手上路

Rank: 1

积分
36
发表于 2024-4-7 03:56:48 | 显示全部楼层
这里的 constexpr 的作用是在编译期即可得到常量结果,无须分配空间。
而用 const 限定是运行时的常量,可能需要给它分配空间。
回复

使用道具 举报

0

主题

206

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2024-4-7 03:57:44 | 显示全部楼层
最开始那段代码有BUG
for(i=1;i<7;i++)printf("%lf,",SIGMA(i));
目测会炸
回复

使用道具 举报

0

主题

184

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2024-4-7 03:58:25 | 显示全部楼层
我的理解就是constexpr的修饰对象是表达式,是一块代码,[代码段],让编译器在编译期可以确定常量的值,但不能保证,所以如果不能确定的话,就会退化成 运行期的工作了。这样的好处就是不用写两套代码了。
=====
而const的修饰对象是变量,是有内存分配的、是[数据段]

另外,我觉得在精神上,这段代码已经足够简明了。
inline constexpr auto SIGMA( std::size_t n ) noexcept
{
    using D7 = double[ 7 ];

    return D7{ 0.0, 0.3085375, 0.6914625, 0.9331928, 0.9937903, 0.9997674, 0.9999966 }[ n ];
}
再往下玩,基本上就是语法糖层面的feature了。
回复

使用道具 举报

0

主题

173

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2024-4-7 03:58:32 | 显示全部楼层
赞成 wayne 的观点!尤其是对 constexpr 限定作用描述,更全面更准确。

我的目的是从一个常量数组中获取指定下标的数值,而这个数组是临时的,无需分配空间,甚至可以是无名或匿名的。

上面引用的代码,还不得不定义一个新类型“D7”,
我的疑问是:可不可省掉这一步?
即:
{} 初始化的数组,让编译器自动识别出类型及大小,可以吗?
回复

使用道具 举报

0

主题

212

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2024-4-7 03:58:50 | 显示全部楼层
如果大小不确定,可以不指定大小
  1. constexpr double SIGMA( size_t n ) noexcept{    return (double[]){ 0.0, 0.3085375, 0.6914625, 5,0.9331928, 0.9937903, 0.9997674, 0.9999966 }[n];}
复制代码
回复

使用道具 举报

0

主题

172

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2024-4-7 03:59:50 | 显示全部楼层
上面的写法之前我曾试过,但很遗憾,未编译通过,我用的是 VS2017
回复

使用道具 举报

0

主题

179

帖子

4

积分

新手上路

Rank: 1

积分
4
发表于 2024-4-7 04:00:22 | 显示全部楼层
确实,查了下。visual studio的C和C++编译器都不支持 compound literal 方式的构造.
https://stackoverflow.com/questi ... nd-literals-in-msvc

------------------------
但是gcc是可以的,测试了下,Linux的和windows的MinGW都支持
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|hrefspace

GMT+8, 2024-12-5 03:06 , Processed in 0.070775 second(s), 21 queries .

Powered by hrefspace X3.4 Licensed

Copyright © 2022, hrefspace.

快速回复 返回顶部 返回列表