2011-01-23

unionの暗黙のデフォルトコンストラクタ

こう書いてある。

12.1 Constructors [class.ctor] paragraph 5

A defaulted default constructor for class X is defined as deleted if:
(省略)
any *non-variant* non-static data member of const-qualified type (or array thereof) with no brace-or- equal-initializer does not have a user-provided default constructor,

X is a union and *all* of its variant members are of const-qualified type (or array thereof),

non-variantという条件があるから、一つ目の条件は、variant memberには当てはまらない。つまり、unionには当てはまらない条件である。(おそらく規格外ではあまり使われていないだろうが、unionの共用されるデータメンバーには、規格ではvariant memberという名称がある。)

二つ目の条件には、all of its variant membersとある。とすれば、const-qualified typeとconst-unqualified typeの両方をvariant memberに持つunionのデフォルトコンストラクターは暗黙にdeletedされないはずである。ということは、以下のコードはwell-formedということになる。

union X
{
   int a ;
   int const b ;
} ;

int main ()
{
   X x ; // well-formed
}

しかし、MSVC、GCC、Comeauは、すべて、エラーとする。

もちろん、これらのコンパイラーは、まだC++0xを完全に実装していない。しかし、このような根本的な言語仕様は、C++03から変わっていないのではないだろうか。C++03の規格の定義では、「もし、ユーザーによって書かれた、暗黙のデフォルトコンストラクターと同等のコードがill-formedになる場合は、ill-formedである」などと定義されている。C++0xでは、explicitly-defaulted functionや、deleted definitionがあるので、いつdeleted定義されるのかというルールを詳細に記述している。そのルールは、C++03を受け継いでいるはずだ。このような根本的な仕様がC++0xで変更されたのだろうか。

不思議に思って質問してみると、だいぶ最近の、Core issue 922による変更らしい。2009年の11月だ。

結論として、unionのvariate memberは、constと非constな型を混ぜて使える。その際、ひとつでも非constな型があれば、暗黙のデフォルトコンストラクターが使える。

ところで、C++0xのunionは、コンストラクターやデストラクターも含むメンバー関数を持てるので、だいぶ様変わりしている。C++0xでは、unionはかなり使いやすくなったはずだ。

No comments: