V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GeruzoniAnsasu
V2EX  ›  C++

最近发现的 C++ 笑话: switch(a){ case 1: return 1;}

  •  
  •   GeruzoniAnsasu ·
    pnck · 246 天前 · 3700 次点击
    这是一个创建于 246 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想必大家都听说过「 Java 程序员的吐槽」说低水平的同事写出这种代码:

    if(status == A) {
      playwith(A);
    }
    if(status == B) {
      playwith(B);
    }
    //...
    

    然后这种吐槽的下面还会有不少人煞有介事地分析,说可能是老代码删改留下的痕迹,以前没有一个统一的 playwith() 函数云云……

    今天很高兴地通知大家,我们 c++,即使是 新代码,也完全可能 会写出这种段落,而且这种段落完全 有意义! :)

    Make sense 的关键在于, playwith()函数 不再一定能 在当前的函数上下文调用了。 c++20 引入的 consteval function 会阻止传入任何非 constexpr 的参数,所以你在一个运行时的 switch context 里是不能用运行期值去调用 consteval 函数的:

        // this lambda is conteval
        auto flatten = [](E _e) consteval {
            auto [id, extra] = static_map(_e);
            auto [name, info] = std::move(extra);
            return make_tuple(static_cast<int>(_e), id, name, info);
        };
    
        cout << std::apply(
            [](auto &&...args) {
                return std::format("in case {}, id {} (name:{}) has info: {}\n",
                                   args...);
            },
            // flatten(FOO));  // work, but only with literal
            to_runtime(flatten, e));  // work at runtime
    

    那这个 to_runtime() 怎么写呢? —— 没错,只能判断每个可能的编译期值了,于是我们得到了

    switch(c){case 1: consteval_fn(1);}
    

    在 compiler explorer 上查看这个例子
    例子 on gist

    p.s. consteval 函数编译起来是真的很慢,为了这样一个 编译期 map 代价还挺大的

    15 条回复    2024-05-17 19:09:58 +08:00
    chesha1
        1
    chesha1  
       246 天前
    没太理解这么做的意思

    consteval 函数最好是比较简单的单纯计算,所以我会声明它为 consteval 希望能在编译器搞完

    如果需要传入任何非 constexpr 的参数了,说明这个函数需要依赖复杂的上下文,为什么还要用 consteval ?在编译期又不一定能提速,开发麻烦,速度还不一定快
    GeruzoniAnsasu
        2
    GeruzoniAnsasu  
    OP
       246 天前
    @chesha1 consteval 函数可以方便实现复杂的编译期 map ,但要在运行时查取这个 map 就会回到 switch 运行时值 case 编译期值的情况,然后 case CONST f(CONST) 就「看起来比较蠢但这里是 c++」
    nicaiwss
        3
    nicaiwss  
       246 天前 via iPhone
    @GeruzoniAnsasu 编译期 map 有啥用?能举个例子吗?什么场景会用到?
    InkStone
        4
    InkStone  
       246 天前
    这个点很有意思,不过从实用性角度考虑的话感觉不如写个脚本去生成硬编码的代码。
    MoYi123
        5
    MoYi123  
       246 天前
    要在编译期算运行期的值只能打表啊, 这也没办法.
    lxdlam
        6
    lxdlam  
       246 天前   ❤️ 2
    本质的核心问题是 C++ 没有真正的 exhaustive 的 enum ,导致编译器无法限定 `E` 的值在一个可优化的 immedate value 范围内,无法将其在 comptime 求出来,所以将其放到参数里无法做编译期生成。

    为什么 `to_runtime` 又能 work 了?因为在当前场景下,编译器推导出来对于 `consteval` 函数 `flattern`,可行的值是有限的,所以能够正常编译。把最后一个分支改为 `f(_e)`,编译器会报错 `f` 为一个 `consteval function`,但是参数是 comptime unknown 的。

    对于有 exhaustive enum 的语言( rust 、zig 等),要实现这种需求应该是 trivial 的。
    lxdlam
        7
    lxdlam  
       246 天前
    @lxdlam 补一句,通过 template + if constexpr + static_assert 可能可以将这个 `to_runtime` 自动化生成出来,不过我也好久没写过 C++ 了,如果不行当我没说。
    cybort
        8
    cybort  
       246 天前 via Android
    这相当于编译器给你打表,看着是 consteval_fn(1),其实这里是一个常数,但是写常数看不出是怎么来的。
    lostsummer
        9
    lostsummer  
       246 天前
    实在忍不了。GoLang 中类型断言就是觉得有点丑陋但不得不用的东西,到 C++中能麻烦 3 倍!
    GeruzoniAnsasu
        10
    GeruzoniAnsasu  
    OP
       246 天前
    @lostsummer

    你好,有种东西叫 typescript

    而且 c++的类型体操其实是越发展越简单的,新标准一直在引入能简化旧 trick 的写法 —— 除了我还未能一窥真容的 executors
    flax5a98aa2
        11
    flax5a98aa2  
       246 天前
    为什么要把打表写成 consteval 函数,而不是 constexpr 函数啊 o_o ....?想要保证 consteval ,写个新的 consteval 函数,转发参数到写好的 constexpr 函数上就行了。
    GeruzoniAnsasu
        12
    GeruzoniAnsasu  
    OP
       246 天前
    @flax5a98aa2 我(们)离最佳实践还很远,较真来说。

    写 c++代码与其它语言最大的区别是,经常要从一大堆实现方法中 filter 出一个标准,而不是突破语言的限制尽可能地让程序灵活起来。

    所以 —— 我不知道。 在确定 consteval 真的很有用之前我也宁愿普通地打表,更何况过去的那些代码生成器也不会给你生成新写法的代码。
    ljyst
        13
    ljyst  
       246 天前
    这算什么。更底层的写单片机为了节省编译后的程序大小能从 500 字节压到 100+并且不是程序压缩而是手工去做,压缩前的版本单字节变量名或者写法这些自己和圈子老手一看就能看懂
    flyqie
        14
    flyqie  
       245 天前 via Android
    请教下,大家生产环境会用这些看起来。。比较魔法的特性吗。

    感觉好像我自己看到的 cpp code 都不太会用这种奇奇怪怪的魔法,写法都很清真。。
    nooneanyone
        15
    nooneanyone  
       222 天前
    @GeruzoniAnsasu #10 确实,这几天做老项目的代码迁移兼容,c++17+的代码改成 c++11 差点没把握整死了。后来还是打算用 17 编译不过不用高版本的 stl 库,这样来跑在旧环境。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5956 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:23 · PVG 10:23 · LAX 18:23 · JFK 21:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.