読者です 読者をやめる 読者になる 読者になる

ボレロ村上 - ENiyGmaA Code

中3女子です。

C++14 のリテラル型

中3女子です。


C++14 でリテラル型の定義にも変更があるので、前回の記事と併せて読んで戴きたく。

    • N3690 § 3.9 Types - 10 より抜粋

― void; or
― a scalar type; or
― a reference type; or
― an array of literal type other than an array of runtime bound; or
― a class type (Clause 9) that has all of the following properties:
 ― it has a trivial destructor,
 ― it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
 ― all of its non-static data members and base classes are of non-volatile literal types.


C++11 からの変更点は、以下の点である。

void がリテラル型になった

これはまあ当然の改訂だ。
返値が void の関数も constexpr 関数にできるようになったし、void はリテラル型として扱われるべきである。

参照型について

参照型は以前からリテラル型であったが、C++11 では「リテラル型への参照型」となっていた。
N3690 では、どうやらリテラル型への参照に限らず、一般の参照型がリテラル型になるようだ。
これについては、どういう意味があるかよく分からない。
一般のポインタ型はリテラル型であるので、参照についてもそれに合わせるということかもしれない。

配列型について

リテラル型の配列型はリテラル型である。
C++14 では新たに動的配列の機能が追加されるため、動的配列はリテラル型でない旨が追記されている。

リテラルクラスについて

メンバ初期化子に関する記述が丸ごと削除されている。
単純に解釈すれば、メンバ初期化子の式が定数式でなくてもよい、ということだ。
つまり以下のようなコードが C++14 では合法ということになる。

int g = 0; // グローバル変数

struct LiteralType {
    int t = g;
    explicit constexpr LiteralType(int t) : t(t) { }
};

constexpr auto t = LiteralType(-1);
//constexpr auto t = LiteralType{}; // error!

メンバ初期化子の式がグローバル変数を参照しているから定数式ではないが、実際にその初期化子が使われずコンストラクタで初期化される限りは問題ない。


ところで、このコードは C++11 に準拠しているはずの GCC4.8.1 および Clang3.3 でエラーなくコンパイルできた。
何故だろうか。
自分の規格の読み違えか、あるいは処理系のバグか。
もしくは、処理系側で実装してみたらメンバ初期化子の制限は別になくても問題ないということになって、規格側がそれに追従したということも考えられる。


なお、これらの記述はドラフトのものであり C++14 として確定したものではないので、以降の議論でまた改訂される可能性があるので、留意されたし。