Почему эта статическая функция-член constexpr не вызывается как constexpr при вызове?

Почему это constexprstatic функция-член, определяемая //! 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
}

Отчеты 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_ данные работают, и, почему такое правило (не имеет смысла для меня)?

2 ответа

Решение

По памяти тела функций-членов оцениваются только после того, как класс полностью определен.

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 член данных класса, класс неполный. Инициализатор может видеть только объявления членов, которые предшествуют ему, и любые функции-члены, которые он видит, считаются объявленными, но не определены. Вызов функции, которая объявлена, но не определена, не может быть константным выражением.

Другие вопросы по тегам