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



为什么这个由//! Nah注释标识的constexpr static成员函数在调用时不被视为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
}

MinGW g++5.1报告

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):错误C2131:表达式未计算为常量constexpr.cpp(12):注意:失败是由调用未定义的函数或未声明为"constexpr"的函数引起的constexpr.cpp(12):注意:请参阅"Item_id::static_n_items"的用法

我的文本编辑器坚持调用中的名称与函数定义中的名称相同。

它似乎与不完整的类有关,因为定义了OUT_OF_CLASS,它可以很好地编译。

但为什么n_items_数据有效,为什么这样的规则(对我来说没有意义)?

在内存中,成员函数体只有在类完全定义后才会求值。

static constexpr int bah = static_n_items(); 

是类定义的一部分,但它引用了一个(静态)成员函数,该函数还不能定义。

解决方案:

将常量表达式推迟到基类并从中派生。

例如:

struct Item_id_base
{
    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
};
struct Item_id : Item_id_base
{
    #ifndef OUT_OF_CLASS
        static constexpr int bah = static_n_items();            // now OK
    #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
}

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

因为这是非法的:

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

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

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

最新更新