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

关于 constexpr 的疑问

  •  
  •   paparika · 2018-06-06 17:27:26 +08:00 · 2252 次点击
    这是一个创建于 2363 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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-06-06 17:36:14 +08:00
    constexpr 也要遵守基本法。c++类成员声明不接受赋值啊。
    paparika
        2
    paparika  
    OP
       2018-06-06 17:43:54 +08:00
    @enenaaa static constexpr int y = 0; 能过,这个算初始化不算赋值?
    enenaaa
        3
    enenaaa  
       2018-06-06 17:46:22 +08:00
    不好意思, 我忘了 static 变量是可以的
    wens07
        4
    wens07  
       2018-06-06 17:48:03 +08:00
    getInt 是一个 expresion,这样不行的吧
    paparika
        5
    paparika  
    OP
       2018-06-06 17:48:50 +08:00
    编译器报的 error: ‘ static constexpr int TestClass1::getInt()’ called in a constant expression
    wwqgtxx
        6
    wwqgtxx  
       2018-06-06 17:49:08 +08:00
    GCC 的提示说的挺清楚的了吧
    error: 'static constexpr int TestClass1::getInt()' called in a constant expression before its definition is complete
    wwqgtxx
        7
    wwqgtxx  
       2018-06-06 17:50:32 +08:00
    也就是说这样写是可行的
    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-06-06 17:55:33 +08:00
    @wwqgtxx 不太理解,信息给足了啊,怎么还不算 complete,有反例吗
    wwqgtxx
        9
    wwqgtxx  
       2018-06-06 17:58:15 +08:00
    @paparika 他的意思是只能在类的定义完成之后才能以 constexpr 的形式调用,至于为什么,你可能需要翻翻 C++的标准了
    paparika
        10
    paparika  
    OP
       2018-06-06 18:00:21 +08:00
    @wwqgtxx 暂时这么强行理解了,thx
    vsomeone
        11
    vsomeone  
       2018-06-06 18:37:09 +08:00
    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-06-06 23:38:50 +08:00
    @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-06-06 23:44:11 +08:00
    @gnaggnoyil 干……发错.演示地址是这个: https://wandbox.org/permlink/hDmeC12PUHPRmoPp
    paparika
        14
    paparika  
    OP
       2018-06-07 09:16:17 +08:00
    @vsomeone
    @gnaggnoyil

    厉害厉害!
    alqaz
        15
    alqaz  
       2018-06-08 17:30:31 +08:00
    @gnaggnoyil 是不是可以理解成编译器处理模板在处理 constexpr 之前,加了模板参数之后,先扫描一边 TestClass1,此时编译器对 TestClass1::getInt() constexpr 函数已经知道了。然后处理 constper 相关的计算也就可以了。
    gnaggnoyil
        16
    gnaggnoyil  
       2018-06-08 17:49:36 +08:00
    没仔细读 GCC 和 Clang 的源码.不过它们都是支持 two-phase lookup 的而你理解的这种行为按照 two-phase lookup 的要求是 ill-formed,虽然没要求有 diagnostics...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6123 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 06:15 · PVG 14:15 · LAX 22:15 · JFK 01:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.