2016-11-18 11 views
2

私は、自分自身の複数の静的なconstexpr値を持つクラスを作成しようとしています。 constexpr宣言では、クラス宣言の内部では使用できないクラスの定義が必要であるため、これは許可されていないようです。私の最初の試みのMCVは、このように見えた:constexprメンバ変数のネストされたクラスの問題

struct A { 
    constexpr A(float x) : _x(x) {} 
    float _x; 

    static constexpr A y = A(1.f); 
    // gcc-5.1: 
    // error: invalid use of incomplete type 'struct A' 
    // static constexpr A y = A(1.f); 
    //       ^
    // msvc-14: 
    // error C2027: use of undefined type 'A' 
    // note: see declaration of 'A' 
    // note: see declaration of 'A' 
    // error C2079: 'public: static A const A::y' uses undefined struct 'A' 
}; 

私の次の試みは、「定数」クラス(データクラスへの暗黙的な変換で、ここには示していない)を宣言しました。

struct B_constant { 
    constexpr B_constant(float x) : _x(x) {} 
    float _x; 
}; 

struct B { 
    static constexpr B_constant y = B_constant(1.f); 
}; 

しかし、それは少し醜いですので、私は、私は一定のクラスにデータクラスの入れ子になったクラスを作ってみたいと思ったが、これはない作業を行います:これは正常に動作するようです

struct C { 
    struct C_constant { 
     constexpr C_constant(float x) : _x(x) {} 
     float _x; 
    }; 

    static constexpr C_constant y = C_constant(1.f); 
    // gcc-5.1: 
    // error: 'constexpr C::C_constant::C_constant(float)' called in a constant expression 
    // static constexpr C_constant y = C_constant(1.f); 
    //            ^
    // msvc-14: 
    // error C2131: expression did not evaluate to a constant 
    // note: failure was caused by call of undefined function or one not declared 'constexpr' 
    // note: see usage of 'C::C_constant::C_constant' 
}; 

私は、constexprのコンストラクタを宣言したが、それはデータクラスで使われていた後、それを定義する際に障害がエラーに類似していたことに気づい:

struct D_constant { 
    constexpr D_constant(float x); 
    float _x; 
}; 

struct D { 
    static constexpr D_constant y = D_constant(1.f); 
    // gcc-5.1: 
    // error: 'constexpr D_constant::D_constant(float)' used before its definition 
    // static constexpr D_constant y = D_constant(1.f); 
    //            ^
    // msvc-14: 
    // error C2131: expression did not evaluate to a constant 
    // note: failure was caused by call of undefined function or one not declared 'constexpr' 
    // note: see usage of 'D::D_constant::D_constant' 
}; 

constexpr D_constant::D_constant(float x) : _x(x) {} 

第3の例で何が起こっているのか誰にでも光を当てることができますか?ネストされたクラス宣言が完了しているにもかかわらず、コンパイラはネストされたクラス内でconstexprコンストラクタの定義を見つけることができないようです。誰かが私がやろうとしていることを達成するためのより良い方法を知っていますか?

+1

'C'は不完全な型です。 'C_constant'は' C'のメンバです。したがって、それは不完全な型のメンバであるため、使用することはできません。それが完了したかどうかにかかわらず、あなたの視点からはならない。 – skypjack

+0

@skypjackネストしたクラスは親クラスが完成するまで効果的に不完全になりますが、それは間違いありませんか?この行動の原動力は何ですか? – Qartar

+0

'A'に' A'のインスタンスが含まれていれば(これには 'A'のインスタンスも含まれていなければなりません)、コンパイルや実行時に関係なく、無限のメモリがインスタンス化される必要があります時間。いくつかの抜け穴がないかぎり、私は 'constexpr'がいつ関わったのか分からない。 –

答えて

0

としてはhereを述べ:

クラスは、クラス指定の閉鎖}で完全に定義されたオブジェクトのタイプ(または完全なタイプ)であると考えられます。 [...]そうでなければ、それ自身のクラスメンバ指定の中では不完全とみなされます。

ここで、[...]は、ネストされたクラスに言及しない例外のリストです。

This部材仕様を定義:

クラス定義の部材仕様は、クラスのメンバーのフルセットを宣言する。メンバーはどこにも追加できません。クラスのメンバーは、データメンバー、メンバー関数、ネストされた型、列挙子、およびメンバーテンプレートとその特殊化です。 [...]

したがって、入れ子になったクラスは、クラス仕様の一部とみなされ、あなたは完全なタイプを(それが言及した例外を脇に置き、決算}である)を持つまで言及することはできません。
データメンバーもメンバー仕様の一部であり、そのようなメンバーの宣言時点では、クラスは不完全とみなされる必要があります。
名前C_constantを使用すると、実際には修飾名C::C_constantが使用されています。これはCの定義の一部です。あなたがCのより短い識別子でそれを参照できるという事実はその性質を変えません。

+0

関連するセクションが標準であることを確認する時間を割いていただきありがとうございますが、私は文言がこの動作を必要としていることを完全には確信していません。クラスメンバの仕様内では、クラスは[...]内で完全であるとみなされ、**デフォルトのメンバ初期化子**(ネストされたクラスではそのようなものを含む)とみなされます。 " (強調鉱山)。さらに、Cのメンバ指定が不完全ではあるが、ネストされたクラスが親クラスのメンバ仕様の中で完全であるとはみなされないことを意味する何も表示されない。私は何が欠けていますか? – Qartar

+0

@Qartar詳細を尋ねた3番目の例は、デフォルトのメンバー初期化子とは関係ありません。 'y'に_brace-or-equal-initializer_があります。 [ここ](http://eel.is/c++draft/class.mem#8)(emphasis mine)を参照してください - 静的でないデータメンバの場合はブレースまたはイコールイニシャライザ** **はmember_のデフォルトメンバー初期化子。 – skypjack

0

誰かが私がやろうとしていることを達成するためのよりよい方法を知っていますか?

A::yは、関数またはファンクタではなく、オブジェクトであることが重要です。 そうでなければ、障害物を回避することができます:

struct A { 
    constexpr A(float x) : _x(x) {} 
    float _x; 

    static constexpr A y() { 
     return A(1.f); 
    } 
}; 

constexpr A y = A::y(); 
static_assert(y._x == 1.f,""); 
関連する問題