implicit constructorか否か
このようなコードが貼り付けられていた。
struct X{constexpr X(){}}; class CC{ struct Y{ constexpr Y(){}; }; struct Z{ /*constexpr Z(){}*/ }; static constexpr X x={}; static constexpr Y y={}; static constexpr Z z={}; }; int main(){}
これは、static constexpr Y y={};
の部分でエラーとなる。なぜだろうか。
順番に見ていく。Xは、別のクラスであるためstaticとの兼ね合いで生成されるタイミングを考慮する必要はない。よってコンパイルが成功する。
Yのコンストラクタはconstexprのため、非implicit生成のコンストラクタである。staticメンバ変数は
[Note: Once the static data member has been defined, it exists even if no objects of its class have been created. [ Example: in the example above, run_chain and running exist even if no objects of class process are created by the program. — end example ] — end note ] - N4606 § 9.2.3
であるので、Yのコンストラクタを起動しなければならないが恐らくデフォルトでないコンストラクタがこの時点では生成されないのだろうか、constant expressionで初期化しろという旨のエラーを吐かれる。struct Z
はimplicit生成のコンストラクタであるが
If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr. - N4606 § 12.1
にある通り要件を満たしているためconstexprコンストラクタがimplicit生成される。これはつまり、トライバルであるか否か等とは異次元にYとZ両者の違いは、implicit生成かそうでないかである。その部分で、staticメンバ変数の初期化タイミングに間に合うかどうかが変わってくるという事だろうか。
さらに不思議なのが、yの初期化にUniform Initializationを使わず通常の括弧で表記した場合、コンパイルが通る。
class CC{ struct Y{ constexpr Y(){}; }; //... static constexpr Y y(); };
これは恐らくある一定のまやかし(as-if)で、y関数の宣言と見なされているのではないだろうか。
要するに今知りたい事をまとめると、implicit生成されたコンストラクタとそうでないコンストラクタにはコンパイラに捉えられるタイミングの差というものがある事が表面化されている規格書内の文書であるのだが、とりあえず時間がないので一旦切り上げ。それか...根本的に違う点で起きている事なのだろうか。