C++ 为什么调用此constexpr静态成员函数时不将其视为constexpr?

C++ 为什么调用此constexpr静态成员函数时不将其视为constexpr?,c++,constexpr,C++,Constexpr,为什么这个constepr静态成员函数由/]标识!Nah注释,在调用时不被视为constexpr struct Item_id { enum Enum { size, position, attributes, window_rect, max_window_size, _ }; static constexpr int n_items_ = _; // OK constexpr auto

为什么这个
constepr
静态成员函数由
/]标识!Nah
注释,在调用时不被视为
constexpr

struct Item_id
{
    enum Enum
    {
        size, position, attributes, window_rect, max_window_size, _
    };

    static constexpr int n_items_ = _;                          // OK
    constexpr auto member_n_items() const -> int { return _; }  // OK
    static constexpr auto static_n_items() -> int { return _; } // OK
    static constexpr int so_far = n_items_;                     // OK
    #ifndef OUT_OF_CLASS
        static constexpr int bah = static_n_items();            //! Nah.
    #endif
};

constexpr auto n_ids() -> int { return Item_id().member_n_items(); }    // OK

auto main() -> int
{
    #ifdef OUT_OF_CLASS
        static constexpr int bah = Item_id::static_n_items();   // OK
    #endif
}
mingwg++5.1报告

constexpr.cpp:12:46: error: 'static constexpr int Item_id::static_n_items()' called in a constant expression static constexpr int bah = static_n_items(); //! Nah. constexpr.cpp:12:46:错误:“static constexpr int Item_id::static_n_items()”在常量表达式中调用 static constexpr int bah=static_n_items();/!不。

Visual C++ 2015报告

constexpr.cpp(12): error C2131: expression did not evaluate to a constant constexpr.cpp(12): note: failure was caused by call of undefined function or one not declared 'constexpr' constexpr.cpp(12): note: see usage of 'Item_id::static_n_items' constexpr.cpp(12):错误C2131:表达式的计算结果不是常数 constexpr.cpp(12):注意:失败是由调用未定义的函数或未声明为“constexpr”的函数引起的 constexpr.cpp(12):注意:请参阅“Item\u id::static\u n\u items”的用法 我的文本编辑器坚持调用中的名称与函数定义中的名称相同

它似乎与不完整的类有关,因为定义了
OUT\u OF\u class
,它可以很好地编译


但是为什么
n\u项
数据起作用,为什么这样的规则(对我来说没有意义)?

从内存中,成员函数体只有在类被完全定义之后才被评估

static constexpr int bah = static_n_items(); 
构成类定义的一部分,但它引用的是一个(静态)成员函数,该函数尚未定义

解决方案:

将常量表达式延迟到基类并从基类派生

e、 g:

为什么你认为标准不允许它

因为这是非法的:

struct Item_id
{   
    // ... etc.

    #ifndef OUT_OF_CLASS
        static constexpr int bah;// = static_n_items();            //! Nah.
    #endif
};

constexpr int Item_id::bah = static_n_items();
并且constexpr必须具有constexpr定义。我们唯一能定义它的地方是在它的声明期间

。。。因此,通过推论,它不能指的是身体尚未定义的任何功能

我不知道该在标准中寻找到哪里。可能有5个不同的、看似不相关的子句:)

[class.mem]/2

在类成员规范中,类在函数体、默认参数、异常规范和默认成员初始值设定项(包括嵌套类中的此类内容)中被视为是完整的。否则,在其自身的类成员规范中,它被视为不完整的


在类的
静态
数据成员的初始值设定项中,该类是不完整的。初始值设定项只能看到它前面的成员声明,它可以看到的任何成员函数都被视为已声明但未定义。对已声明但未定义的函数的调用不能是常量表达式。

gcc6.1和clang3.8也不喜欢它。请注意,将
bah
的声明和初始化移出
struct
并执行
static constexpr int bah=Item_id::static_n_items()使其在G++5上编译。3@GillBates:谢谢,我也发现了同样的问题(见修改后的问题)。很奇怪,我想你可能是对的,谢谢!,但我一直认为重写(在类之后使用函数定义)只是一个概念工具。我记不起在《标准》中见过它。“那么,好吧,你知道标准的哪一部分规定了这一点吗?”Cheersandhth.-Alf三心二意的回答补充到了答案中。在漫长的一天结束后,我没有勇气去拖拽所有相关条款的标准。。。我相信你知道这种感觉!谢谢你把它挖出来![basic.scope.class]/1用稍微不同的语言说了几乎相同的事情,但我还没有找到一个引用来支持我的说法,即“它可以看到的任何成员函数都被认为是声明的,但没有定义的”。
struct Item_id
{   
    // ... etc.

    #ifndef OUT_OF_CLASS
        static constexpr int bah;// = static_n_items();            //! Nah.
    #endif
};

constexpr int Item_id::bah = static_n_items();