- cpp20[meta cpp]
このページはC++20に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
C++20では、要素数が既知の配列型から要素数不明の配列型への暗黙変換が可能になる。
int[10] // 要素数が既知の配列
int(*)[10] // 要素数が既知の配列へのポインタ
int(&)[10] // 要素数が既知の配列への参照
int[] // 要素数不明の配列
int(*)[] // 要素数不明の配列へのポインタ
int(&)[] // 要素数不明の配列への参照
int arr[1];
int(&r)[] = arr; // C++17ではエラー、C++20ではOK
int(*p)[] = &arr; // C++17ではエラー、C++20ではOK
オーバーロード解決において、配列の要素の型が同じで要素数が一致する候補がある場合、要素数が未知の配列より優先される。
#include <iostream>
void f(int (&&)[] ){ std::cout << "#1 called\n"; } // #1
void f(double (&&)[] ){ std::cout << "#2 called\n"; } // #2
void f(int (&&)[2]){ std::cout << "#3 called\n"; } // #3
int main()
{
f({1}); // #1を呼ぶ: 型が一致していて、要素数が一致する候補がないため#1になる。
f({1.0}); // #2を呼ぶ: 浮動小数点数からの変換はdoubleとintならdoubleが選ばれる。
f({1.0, 2.0}); // #2を呼ぶ: 浮動小数点数からの変換はdoubleとintならdoubleが選ばれる。
f({1, 2}); // #3を呼ぶ: 要素数が明示されている方が優先されるので#1にはならない。
// また、型が一致する方が優先されるので#2にはならない。
}
#include <iostream>
void f(int(&&)[]){ std::cout << "unknown bound\n"; }
void f(int(&&)[0]){ std::cout << "bound 0\n"; }
void f(int(&&)[2]){ std::cout << "bound 2\n"; }
void f(int(&&)[4]){ std::cout << "bound 4\n"; }
void g(int(&&)[]){ std::cout << "unknown bound\n"; }
void g(double(&&)[0]){ std::cout << "bound 0\n"; }
void g(double(&&)[1]){ std::cout << "bound 1\n"; }
void g(double(&&)[2]){ std::cout << "bound 2\n"; }
int main()
{
std::cout << "f:\n";
f({});
f({0});
f({0, 0});
f({0, 0, 0});
f({0, 0, 0, 0});
f({0, 0, 0, 0, 0});
std::cout << "g:\n";
g({0});
g({0, 0});
g({0, 0, 0});
g({0.0, 0.0});
}
f:
bound 0
unknown bound
bound 2
unknown bound
bound 4
unknown bound
g:
unknown bound
unknown bound
unknown bound
bound 2
従来、配列から要素数不明の配列への変換はできなかった。 しかし、この制限には強い理由がなかったので、変換を許すことになった。
void f(int(&)[]); // 要素数不明の配列への参照(を引数に取る関数)
void g(int(&)[1]); // 長さ1の配列への参照
int arr[1];
f(arr); // C++17ではエラー、C++20ではOK
int(&r)[] = arr; // C++17ではエラー、C++20ではOK
g(arr); // OK