C++ で参照渡しで配列を受け取るファンクターを使って配列を初期化することは可能か?
どういう意味なのか
void initializeArray(int (&array)[5]) {
// ... array を使って初期化する処理 ...
}
int main() {
int array[5] = {};
initializeArray(array);
// ...
}
ここで、initializeArray
関数は、参照渡しで受け取った配列 array
を使って初期化処理を行います。つまり、関数内で array
を変更すると、main
関数に戻ってきた array
も変化していることになります。
C++11 以前では不可能だった理由
C++11 以前では、関数に配列を直接渡すことはできませんでしたが、ポインタを渡すことはできました。そのため、配列を初期化するためにファンクターを使用する場合は、以下のようにポインタを渡す必要がありました。
void initializeArray(int *array, int size) {
// ... array を使って初期化する処理 ...
}
int main() {
int array[5] = {};
initializeArray(array, 5);
// ...
}
しかし、この方法には、以下の問題がありました。
- 関数呼び出し側で配列のサイズを明示的に渡す必要がある
- ポインタ演算が必要になり、コードがわかりにくくなる
C++11 で導入された参照渡し
C++11 では、関数に配列を直接参照渡しで渡すことができるようになりました。これにより、上記の問題を解決することができます。
void initializeArray(int (&array)[5]) {
// ... array を使って初期化する処理 ...
}
int main() {
int array[5] = {};
initializeArray(array);
// ...
}
このコードは、C++11 以前のコードよりも簡潔でわかりやすくなっています。
注意点
C++ で参照渡しで配列を受け取るファンクターを使って配列を初期化する場合、以下の点に注意する必要があります。
- 関数内で渡された配列を
const
修飾する必要がある - 関数内で渡された配列のサイズを変更することはできない
C++11 以降では、参照渡しで配列を受け取るファンクターを使って配列を初期化することが可能になりました。これは、コードをより簡潔でわかりやすくするのに役立ちます。
#include <iostream>
void initializeArray(int (&array)[5]) {
// すべての要素を 1 で初期化
for (int i = 0; i < 5; ++i) {
array[i] = 1;
}
}
int main() {
int array[5] = {}; // 初期化されていない配列を宣言
initializeArray(array); // 関数呼び出し
// 初期化された配列を出力
for (int i = 0; i < 5; ++i) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
このコードでは、initializeArray
関数は参照渡しで受け取った配列 array
のすべての要素を 1 で初期化します。
main
関数では、まず要素がすべて 0 で初期化された配列 array
を宣言します。その後、initializeArray
関数を呼び出して array
を初期化します。最後に、初期化された array
の要素を出力します。
このコードを実行すると、以下の出力が得られます。
1 1 1 1 1
解説
このコードは以下の点に注意する必要があります。
initializeArray
関数は、渡された配列をconst
修飾する必要があります。これは、関数内で配列を書き換えることができないようにするためです。initializeArray
関数は、渡された配列のサイズを変更することはできません。サイズの変更が必要な場合は、ポインタを渡す方法を使用する必要があります。
特定の要素だけを初期化したい場合は、以下のコードのように for
ループや範囲ベース for ループを使用することができます。
void initializeArray(int (&array)[5]) {
for (int i = 2; i < 5; ++i) {
array[i] = 2;
}
}
int main() {
int array[5] = {};
initializeArray(array);
// ...
// 特定の要素のみ初期化されていることを確認
for (int i = 0; i < 5; ++i) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
このコードでは、initializeArray
関数は、配列の 2 番目の要素から 4 番目の要素までを 2 で初期化します。
アルゴリズムを使用する
C++ Standard Library には、配列を初期化するための様々なアルゴリズムが用意されています。例えば、以下のように std::fill
アルゴリズムを使用して、配列をすべて同じ値で初期化することができます。
#include <algorithm>
void initializeArray(int (&array)[5]) {
std::fill(array, array + 5, 3);
}
int main() {
int array[5] = {};
initializeArray(array);
// ...
// 特定の要素のみ初期化されていることを確認
for (int i = 0; i < 5; ++i) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
このコードでは、std::fill
アルゴリズムを使用して、配列 array
のすべての要素を 3 で初期化します。
関数オブジェクトを使用する
関数オブジェクトを使用して、配列を初期化することができます。例えば、以下のようにラムダ式を使用して、配列の偶数番目の要素を 2 で初期化することができます。
void initializeArray(int (&array)[5]) {
std::for_each(array, array + 5, [](int& n) {
if (n % 2 == 0) {
n = 2;
}
});
}
int main() {
int array[5] = {};
initializeArray(array);
// ...
// 特定の要素のみ初期化されていることを確認
for (int i = 0; i < 5; ++i) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
return 0;
}
このコードでは、ラムダ式を使用して、std::for_each
アルゴリズムに渡される各要素 n
をチェックし、偶数であれば 2 に書き換えます。
c++ c++17 c++14