关于 constexpr 的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
paparika
V2EX    C

关于 constexpr 的疑问

  •  
  •   paparika 2018 年 6 月 6 日 2683 次点击
    这是一个创建于 2798 天前的主题,其中的信息可能已经有所发展或是发生改变。

    class TestClass1{ public:

    static constexpr int getInt(){return 0;}; static constexpr int y = getInt();//why it's wrong? TestClass1(){} 

    };

    编译失败了,why?

    16 条回复    2018-06-08 17:49:37 +08:00
    enenaaa
        1
    enenaaa  
       2018 年 6 月 6 日
    constexpr 也要遵守基本法。c++类成员声明不接受赋值啊。
    paparika
        2
    paparika  
    OP
       2018 年 6 月 6 日
    @enenaaa static constexpr int y = 0; 能过,这个算初始化不算赋值?
    enenaaa
        3
    enenaaa  
       2018 年 6 月 6 日
    不好意思, 我忘了 static 变量是可以的
    wens07
        4
    wens07  
       2018 年 6 月 6 日
    getInt 是一个 expresion,这样不行的吧
    paparika
        5
    paparika  
    OP
       2018 年 6 月 6 日
    编译器报的 error: ‘ static constexpr int TestClass1::getInt()’ called in a constant expression
    wwqgtxx
        6
    wwqgtxx  
       2018 年 6 月 6 日
    GCC 的提示说的挺清楚的了吧
    error: 'static constexpr int TestClass1::getInt()' called in a constant expression before its definition is complete
    wwqgtxx
        7
    wwqgtxx  
       2018 年 6 月 6 日
    也就是说这样写是可行的
    class TestClass1{ public:

    static constexpr int getInt(){return 0;};

    TestClass1(){}
    };

    class TestClass2{ public:

    static constexpr int y = TestClass1::getInt();//why it's wrong?

    TestClass2(){}
    };
    paparika
        8
    paparika  
    OP
       2018 年 6 月 6 日
    @wwqgtxx 不太理解,信息给足了啊,怎么还不算 complete,有反例吗
    wwqgtxx
        9
    wwqgtxx  
       2018 年 6 月 6 日
    @paparika 他的意思是只能在类的定义完成之后才能以 constexpr 的形式调用,至于为什么,你可能需要翻翻 C++的标准了
    paparika
        10
    paparika  
    OP
       2018 年 6 月 6 日
    @wwqgtxx 暂时这么强行理解了,thx
    vsomeone
        11
    vsomeone  
       2018 年 6 月 6 日
    https://stackoverflow.com/questions/11522399/constexpr-initializing-static-member-using-static-function:

    The most likely reason for this is that constexpr variables have to be available as compile-time constant expressions from inside the bodies of member functions, so the variable initializers are completely defined before the function bodies -- which means the function is still incomplete (undefined) in the context of the initializer, and then this rule kicks in, making the expression not be a constant expression.

    大致意思就是,由于 constexpr 必须是 compile-time known 的,所以它们的 initializer 定义位于它们所在的 function/class 之外。因此,你的代码等价于:

    ```c++

    constexpr int TestClass1::y = initializer_for_y();

    class TestClass1{ public:

    static constexpr int getInt(){return 0;};
    static constexpr int y;//why it's wrong?
    TestClass1(){}
    };
    ```

    但是在 initializer_for_y() 试着调用 getInt() 的时候 TestClass1 尚未定义。这也就是为什么编译器会报告:
    note: undefined function 'getInt' cannot be used in a constant expression
    gnaggnoyil
        12
    gnaggnoyil  
       2018 年 6 月 6 日
    @paparika 然而你现在只能这样强行理解……因为事实上标准中没有任何字句显式要求成员函数的类内定义一定不能在类的内部起效,而只是要求在类内部的时候类是一个不完全类型……换句话说标准没有要求你这种写法一定是错的.事实上你会发现在 Clang 和 GCC 下只要给 TestClass1 加一个模板参数编译错误就嗷的一声不见了…… https://wandbox.org/permlink/MiclIS7tSl4qR91C

    我搜了一下发现 CWG1626( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626)提到了这个问题,然而很明显 WG21 至今仍在无视这个 2013 年就提出来的 CWG...
    gnaggnoyil
        13
    gnaggnoyil  
       2018 年 6 月 6 日
    @gnaggnoyil 干……发错.演示地址是这个: https://wandbox.org/permlink/hDmeC12PUHPRmoPp
    paparika
        14
    paparika  
    OP
       2018 年 6 月 7 日
    @vsomeone
    @gnaggnoyil

    厉害厉害!
    alqaz
        15
    alqaz  
       2018 年 6 月 8 日
    @gnaggnoyil 是不是可以理解成编译器处理模板在处理 constexpr 之前,加了模板参数之后,先扫描一边 TestClass1,此时编译器对 TestClass1::getInt() constexpr 函数已经知道了。然后处理 constper 相关的计算也就可以了。
    gnaggnoyil
        16
    gnaggnoyil  
       2018 年 6 月 8 日
    没仔细读 GCC 和 Clang 的源码.不过它们都是支持 two-phase lookup 的而你理解的这种行为按照 two-phase lookup 的要求是 ill-formed,虽然没要求有 diagnostics...
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     949 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 21:18 PVG 05:18 LAX 13:18 JFK 16:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86