質問するログイン新規登録

Q&A

解決済

1回答

515閲覧

配列への参照について

fana

総合スコア12398

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

2クリップ

投稿2026/04/09 03:06

0

2

ここ を見て,同様のことを試してみているつもりなのですが,話通りにならない様子です.

使用環境:
C++20 の話だということなので, Visual Studio 2022 でコンパイルオプションに /std:c++20 を指定(:プロジェクトのプロパティで「C++ 言語標準」に「ISO C++20 標準」を選択)しています.

  • Q1 : 下記コードで (1)~(3) の箇所がコンパイルエラーになるのは何故でしょうか?
  • Q2 : それはそれとして, int (&)[] のような要素数不明なやつには(このようなオーバーロードの他に)何か有用な用途があるのでしょうか?

C++

1void Test( int ){ std::cout << "int\n"; } 2 3#if 0 //(1)要素数0の関数が作れない(リンク先ページの「例」には存在するのだが) 4//E0094: 配列のサイズは0よりおおきくなければなりません 5//C2084: 関数 'void Test(const int (&)[0])' は既に本体を持っています 6void Test( const int (&)[0] ){ std::cout << "int[0]\n"; } 7#endif 8 9void Test( const int (&)[1] ){ std::cout << "int[1]\n"; } 10void Test( const int (&)[2] ){ std::cout << "int[2]\n"; } 11void Test( const int (&)[3] ){ std::cout << "int[3]\n"; } 12void Test( const int (&)[] ){ std::cout << "int[unknown size]\n"; } 13 14int main() 15{ 16 Test( 1 ); //OK > int 17 18#if 0 //(2) 要素数1だとコンパイルエラーになる 19 //C2668 : オーバーロード関数の呼び出しを解決することができません 20 //(5つの Test() 全ての可能性があると言われる) 21 Test( { 1 } ); 22#endif 23 24 Test( { 1,2 } ); //OK > int[2] 25 Test( { 1,2,3 } ); //OK > int[3] 26 Test( { 1,2,3,4 } ); //OK > int[unknown size] 27 28#if 0 //(3) これらがコンパイルエラーになる. 29 //( const int (&)[] の可能性があると言われる) 30 {//C2668 : オーバーロード関数の呼び出しを解決することができません 31 int arr[1] = { 1 }; 32 Test( arr ); 33 } 34 {//C2668 : オーバーロード関数の呼び出しを解決することができません 35 int arr[2] = { 1,2 }; 36 Test( arr ); 37 } 38 {//C2668 : オーバーロード関数の呼び出しを解決することができません 39 int arr[3] = { 1,2,3 }; 40 Test( arr ); 41 } 42#endif 43 44 {//これはOK 45 int arr[4] = { 1,2,3,4 }; 46 Test( arr ); //OK > int[unknown size] 47 } 48}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

guest

回答1

0

ベストアンサー

C++20 でも配列の長さ 0 は認められていないはずです。 (1) については単純に資料の間違いであると思います。


(2) については結論から言えばコンパイラのバグだと思いますが混乱が起きる事情はあります。

集成体初期化においては初期化子に記述されている要素が不足する場合は 0 が補われるというルールがあります。

たとえば

cpp

1int main() { 2 const int (&foo)[10] = {1 ,2, 3}; 3}

というように要素数を 3 個しか書かなかった場合でも要素数 10 の配列の初期化子として認められるのです。

これは仮引数と実引数の関係においても同じように適用され、

cpp

1#include <iostream> 2 3void Test( const int (&)[10] ){std::cout << "int[10]\n";} 4 5int main() { 6 Test( { 1, 2, 3 } ); 7}

は OK です。

ただし、要素数が完全にマッチするものがあればそれが選ばれるのが正しいです。

cpp

1#include <iostream> 2 3void Test( const int (&)[10] ){std::cout << "int[10]\n";} 4void Test( const int (&)[3] ){std::cout << "int[3]\n";} // こちらが優先される 5 6int main() { 7 Test( { 1, 2, 3 } ); 8}

長さ不定の配列の参照が加わってコンパイラ内で優先順位の処理をする部分がおかしくなったんでしょう。


(3) も単なるバグですね。 オーバーロードの優先順位の規則をまだ実装できていないだけに見えます。


長さ不定の配列の参照の有用性については、配列の先頭を指すポインタが配列の長さを関知しないことに対応づくものなんではないかと思います。

cpp

1void foo(const int *){} 2 3int main() { 4 // ポインタだったら長さは自由 5 // 参照でもやりたくない? 6 int bar[] = {1, 2, 3}; 7 int baz[] = {1, 2, 3, 4, 5}; 8 foo(bar); 9 foo(baz); 10}

投稿2026/04/09 04:44

SaitoAtsushi

総合スコア5896

fana

2026/04/13 13:54

Q1側に関しては,まずはコンパイラ側のバグであろうということで納得しました. (Visual Studio バージョン別の Microsoft C/C++ 言語準拠  https://learn.microsoft.com/ja-jp/cpp/overview/visual-cpp-language-conformance?view=msvc-170 という場所の表を見て,この機能はすでに( VS2019 の時点で)対応済みなのかと思ったのですが……よく見たら「最初に」サポートしたバージョンという話でしかなく,完全に対応したという話ではないのですねこれ) Q2側に関して int (&)[] や int (*)[] について少し考えてみましたが,やはり使いどころは無さそうかな,と思いました. (どうでもいいですが,回答にコメントを書かない状態だと,「フィードバックしていない回答があるからどうにかしろ」という旨のポップアップが毎回表示されるという嫌な仕様になったみたいですね.グッドやベストアンサーでは「フィードバック」とはみなされない様子)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問