litong 发表于 2024-4-7 03:54:29

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

问题是这样:

想获取 \(6\sigma\) 中的某一个值,在 C++11 之前是这么做的:#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 标准后,我们可以这么写了: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 是没有必要的(甚至无需给它命名),可以改写成如下: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 ];}

以上皆能编译通过。



但是,我觉得仍不够“优雅”,觉得理想的代码应该是下面的: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++ 会如何实现它?并尽可能保持优雅。。。

aecupeemow 发表于 2024-4-7 03:55:27

刚刚同事给出一个方案,还算比较“优雅”: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>”

JamesTeest 发表于 2024-4-7 03:55:50

我或许会用const float SIGMA[]={...};,或许不优雅,哈哈。

ehonacatekaq 发表于 2024-4-7 03:56:48

这里的 constexpr 的作用是在编译期即可得到常量结果,无须分配空间。
而用 const 限定是运行时的常量,可能需要给它分配空间。

isebufusiza 发表于 2024-4-7 03:57:44

最开始那段代码有BUG
for(i=1;i<7;i++)printf("%lf,",SIGMA(i));
目测会炸

Charlslots 发表于 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了。

itimowahwafli 发表于 2024-4-7 03:58:32

赞成 wayne 的观点!尤其是对 constexpr 限定作用描述,更全面更准确。

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

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

iwejinawiciru 发表于 2024-4-7 03:58:50

如果大小不确定,可以不指定大小
constexpr double SIGMA( size_t n ) noexcept{    return (double[]){ 0.0, 0.3085375, 0.6914625, 5,0.9331928, 0.9937903, 0.9997674, 0.9999966 };}

ejiwueu 发表于 2024-4-7 03:59:50

上面的写法之前我曾试过,但很遗憾,未编译通过,我用的是 VS2017

dingji 发表于 2024-4-7 04:00:22

确实,查了下。visual studio的C和C++编译器都不支持 compound literal 方式的构造.
https://stackoverflow.com/questi ... nd-literals-in-msvc

------------------------
但是gcc是可以的,测试了下,Linux的和windows的MinGW都支持
页: [1]
查看完整版本: 如何优雅地获取常量数列中某个值?