T(*)[N]
C++ 標準では、固定配列へのポインターまたは参照 (例:またはT(&)[N]
) を、同じ型および CV 修飾子を持つより小さな固定配列へのポインターまたは参照 (例:T(*)[M]
または)に変換することは合法ですかT(&)[M]
?
基本的に、これは、すべてのインスタンス化に対して常に適切に形成されるでしょうか?T
(レイアウトタイプに関係なく):
void consume(T(&array)[2]);
void receive(T(&array)[6])
{
consume(reinterpret_cast<T(&)[2]>(array));
}
以下では、これが有効な変換であるという言及は見当たりません。
T = std::string
ただし、すべての主要なコンパイラはこれを受け入れ、 ( compiler explorer)を使用するときに最適化された場合でも適切なコードを生成するようです(未定義の動作である場合、これはあまり証明されません)。
T[2]
私の理解では、 のオブジェクトは実際には作成されていないため、 の参照は無効になるので、型システムによればこれは違法であるはずですT(&)[2]
。
この質問にタグを付けますC++11 のこれは私が答えに最も興味を持っているバージョンであるためですが、この答えが新しいバージョンでも異なるかどうかを知りたいと思います。
ベストアンサー1
ここで言うことはあまりないがいいえ、どの言語バージョンでも、型は単に無関係です。C++20では から への変換T (*)[N]
(T (*)[]
および参照についても同様)が許可されていますが、これは2つの異なるN
を同等に扱うことができるという意味ではありません。このルールの「参照」に最も近いのは [conv.array]/1(「結果は配列の最初の要素へのポインタです。」)T[2]
であり、これはあなたの例では存在しません。注記[defns.undefined] (「このドキュメントで動作の明示的な定義が省略されている場合、未定義の動作が予想される場合があります」)
コンパイラが「キャッチ」しない理由の一つは、そのようなreinterpret_cast
sは有効期間戻るオブジェクトの実際の型に次々とreinterpret_cast
変換することで、異なる型へのポインタや参照を期待するインターフェース(ただし、使用つまり、与えられたコードは正当だが、の明らかな定義とconsume
呼び出し元receive
は一緒に未定義の動作を引き起こす。(もう1つの理由は、最適化ツールがコードをそのままにしておくことが多いためである。いつもブランチを削除できない限り、未定義です。