この constexpr 静的メンバー関数は、呼び出されたときに constexpr として認識されないのはなぜですか? [重複] 質問する

この constexpr 静的メンバー関数は、呼び出されたときに constexpr として認識されないのはなぜですか? [重複] 質問する

constexpr staticコメントで識別されるこのメンバー関数が//! 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' の使用法を参照してください

私のテキスト エディターは、呼び出し内の名前が関数定義内の名前と同じであることを要求します。

defined を使用すると正常にコンパイルされるため、不完全なクラスと関係があるようですOUT_OF_CLASS

しかし、なぜn_items_データは機能するのでしょうか、そして、なぜそのようなルールが(私には意味をなさないのでしょうか)?

ベストアンサー1

メモリからは、メンバー関数本体はクラスが完全に定義された後にのみ評価されます。

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 つの異なる、一見無関係な条項があると思います :)

おすすめ記事