Why is this constexpr static member function not seen as constexpr when called?

非 Y 不嫁゛ 提交于 2019-11-27 16:00:48

From memory, member function bodies are evaluated only once the class has been completely defined.

static constexpr int bah = static_n_items(); 

forms part of the class definition, but it's referring to a (static) member function, which cannot yet be defined.

Solution:

defer constant expressions to a base class and derive from it.

e.g.:

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
}

Why do you think the standard disallows it?

Because this is illegal:

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();

And a constexpr must have a constexpr definition. The only place we can define it is during its declaration...

... so by deduction it cannot refer to any function who's body is not yet defined.

I am at a loss to know where to look in the standard for all that. Probably 5 different, seemingly unrelated clauses :)

[class.mem]/2

Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and default member initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

In the initializer of a static data member of a class, the class is incomplete. The initializer can only see the declarations of members which precede it, and any member functions it can see are considered declared but not defined. A call to a function that is declared but not defined can not be a constant expression.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!