私の組み込みシステムはC++ 11対応バージョンのg ++を入手したので、コードをクリーンアップしてきました。
for( uint16_t* p = array; p < (&array)[1]; ++p ) {
*p = fill_value;
}
に
for( uint16_t& r : array ) {
r = fill_value;
}
これははるかにより読みやすくなります。
array2[m][n]
のすべての要素で動作する範囲ベースのforループはありますか?
古いバージョンは
for( int16_t* p = array2[0]; p < (&array2)[1][0]; ++p ) {
*p = fill_value;
}
コンパイラがループをフラット化することが保証されていない限り、ネストされたループは必要ありません。
(FWIW、コンパイラはGNU 4.7.4 Linaro g ++ ARM TIコードに同梱されているクロスコンパイラComposerスタジオ6.0.0)
例として、多次元配列の値を出力および操作するさまざまな方法があります。
int arr[2][3] = { { 2, 3, 4 }, { 5, 6, 7} };
最初の方法、
size_t count = 0 ;
for( auto &row : arr)
for(auto &col : row)
col = count ++;
ここで最初のforループでは、2つの配列を参照しています。次に、2番目の配列では、これらのサブ配列の3つの要素を個別に参照しています。また、colにカウントを割り当てています。したがって、サブアレイの次の要素に繰り返し処理されます。
2番目の方法、
for( auto &row : arr)
for( auto col : row)
cout << col << endl;
配列からポインタへの変換を避けたいので、最初のループでここを参照します。
これが行われた場合(エラーの場合:最初のforループは参照ではありません)、
for( auto row : arr) // program won't compile
for( auto col : row)
ここでは、int *が行にあります。 2番目のforループに到達するまでに。行がint *になり、リストではないため、プログラムはコンパイルされません。リストを作成する必要があります。そうすれば、それをranged forループに渡して、そのリストを反復処理するために使用できるのは私たちだけです。
vector<int> list = { *(row+0) , *(row+1) , *(row+ 2) } ;
これで、リストを反復に使用できます
for ( ----- : list)
for ( auto &a : array )
{
for ( int &x : a ) x = fill_value;
}
編集:あなたは以下を試すことができます
const size_t n = 2;
const size_t m = 3;
int a[n][m] = { { 1, 2, 3 }, { 4, 5, 6 } };
for ( auto &x : reinterpret_cast<int ( & )[n * m]>( a ) ) x = 10;
for ( auto x : reinterpret_cast<int ( & )[n * m]>( a ) ) std::cout << x << ' ';
std::cout << std::endl;;
出力は
10 10 10 10 10 10
このアプローチの利点は、2次元配列だけでなく、任意の多次元配列を再解釈できることです。例えば
int a[n][m][k] = { /* some initializers */ };
for ( auto x : reinterpret_cast<int ( & )[sizeof( a ) / sizeof( ***a )]>( a ) )
{
std::cout << x << ' ';
}
std::cout << std::endl;;
(静的に既知のサイズの)任意の配列を埋めるコードを次に示します。
#include <algorithm>
#include <iterator>
#include <type_traits>
template <typename T>
void fill_all(T & a, typename std::remove_all_extents<T>::type v);
template <typename T>
void fill_all_impl(T & a, typename std::remove_all_extents<T>::type v, std::false_type);
template <typename T>
void fill_all_impl(T & a, typename std::remove_all_extents<T>::type v, std::true_type)
{
for (auto & x : a)
fill_all(x, v);
}
template <typename T>
void fill_all_impl(T & a, typename std::remove_all_extents<T>::type v, std::false_type)
{
std::fill(std::begin(a), std::end(a), v);
}
template <typename T>
void fill_all(T & a, typename std::remove_all_extents<T>::type v)
{
fill_all_impl(a, v, std::is_array<typename std::remove_extent<T>::type>());
}
使用例:
int a[3][4][2];
fill_all(a, 10);
@ Ben Voigt の answer (に適用できる)のもう少し一般的なバリアントn-次元配列):
template
<
typename Array,
typename Element = typename std::remove_all_extents<Array>::type,
std::size_t Size = sizeof(Array) / sizeof(Element),
typename FlattenedArray = Element (&)[Size]
>
constexpr FlattenedArray Flatten(Array &a)
{
return reinterpret_cast<FlattenedArray>(a);
}
template
<
typename Array,
typename Element = typename std::remove_all_extents<Array>::type
>
void FillArray(Array& a, Element v)
{
for (Element& e : Flatten(a))
{
e = v;
}
}
// ...
int a[2][3][5];
int d = 42;
FillArray(a, d);
実例 。
ウラドとプラエトリアニの答えの一部を組み合わせて、私は以下を使用することにしました。
template<typename T, size_t N, size_t M>
auto flatten(T (&a)[M][N]) -> T (&)[M*N] { return reinterpret_cast<T (&)[M*N]>(a); }
for( int16_t& r : flatten(array2) ) {
r = fill_value;
}
@ Kerrek SB の one よりも少し単純な(そしておそらく効果が低い)ソリューション
#include <type_traits>
template <typename Type>
void FillArray(Type& e, Type v)
{
e = v;
}
template <typename Type, std::size_t N>
void FillArray(Type (&a)[N], typename std::remove_all_extents<Type>::type v)
{
for (Type& e : a)
{
FillArray(e, v);
}
}
使用例:
int a[2][3][5];
FillArray(a, 42);
多次元配列のすべての要素にファンクターを適用できる、もう少し一般的なソリューション:
template <typename Type, typename Functor>
void ForEachElement(Type& e, Functor f)
{
f(e);
}
template <typename Type, std::size_t N, typename Functor>
void ForEachElement(Type (&a)[N], Functor f)
{
for (Type& e : a)
{
ForEachElement(e, f);
}
}
使用例:
int a[2][3][5];
ForEachElement(a, [](int& e){e = 42;});