С введением нового стандарта С++ 2011 язык С++ настолько изменился, что, фактически, в нем сосуществуют два различных языка, сильно отличающихся друг от друга.
Эта мысль у меня возниклла, когда я решил сам для себя сделать простое задание, опубликованное некоторым студентом на одном из форумов со слезной просьбой помочь ему его сделать.
Формулировка задания звучит довольно просто: в заданной целочисленной матрице в каждой строке поменять элементы, равные нулю, на среднее арифметическое значений элементов отличных от нуля этой же строки. Типичная задача на выработку у студентов навыков по работе с циклами.
Как бы решал эту задачу студент? Очевидно,что ему нужна функция, которая вычисляет среднее арифметическое строки матрицы. Функция могла бы выглядеть так:
int average( int a[], size_t n )
{
int sum = 0;
int count = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( a[ i ] != 0 )
{
sum += a[ i ];
count++;
}
}
if ( count != 0 ) sum /= count;
return ( sum );
}
Далее ему потребовалось бы написать функцию, которая заменяет нулевые элементы в строке средним арифметическим значений элементов этой же строки. Данная функция могла бы выглядеть следующим образом:
void replace_zero( int a[], size_t n, int value )
{
for ( size_t i = 0; i < n; i++ )
{
if ( a[ i ] == 0 ) a[ i ] = value;
}
}
Теперь осталось лишь организовать главный цикл по строкам двумерной матрицы. Этот цикл мог бы выглядеть таким образом, Предположим, что исходная матрица объявлена как
int a[m][n]; for ( size_t i = 0; i < m; i++ )
{
int value = average( a[ i ], n );
if ( value != 0 ) replace_zero( a[ i ], n, value );
}
Ну, и еще можно добавить циклы для вывода исходный и результирующей матриц на консоль.
for ( size_t i = 0; i < m; i++ )
{
for ( j = 0; j < n; j++ )
{
std::cout << a[ i ][ j ] << ' ';
}
std::cout << std::endl;
}
std::cout << std::endl;
Теперь можно все собрать вместе. Для простоты матрица будет задаваться списком инициализации при ее объявлении.
#include <iostream>
int average( int a[], size_t n )
{
int sum = 0;
int count = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( a[ i ] != 0 )
{
sum += a[ i ];
count++;
}
}
if ( count != 0 ) sum /= count;
return ( sum );
}
void replace_zero( int a[], size_t n, int value )
{
for ( size_t i = 0; i < n; i++ )
{
if ( a[ i ] == 0 ) a[ i ] = value;
}
}
int main()
{
const size_t m = 3;
const size_t n = 14;
int a[ m ][ n ] = { { 1, 0, 3, 4, 0, 0, 7, 3, 0, 9, 5, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 7, 5, 0, 0, 0, 11, 1, 4, 0, 2, 0, 0, 1, 9 } };
for ( size_t i = 0; i < m; i++ )
{
for ( j = 0; j < n; j++ )
{
std::cout << a[ i ][ j ] << ' ';
}
std::cout << std::endl;
}
std::cout << std::endl;
for ( size_t i = 0; i < m; i++ )
{
int value = average( a[ i ], n );
if ( value != 0 ) replace_zero( a[ i ], n, value );
}
for ( siize_t i = 0; i < m; i++ )
{
for ( j = 0; j < n; j++ )
{
std::cout << a[ i ][ j ] << ' ';
}
std::cout << std::endl;
}
std::cout << std::endl;
return ( 0 );
}
Я этот код набил здесь же в сообщении от руки и не проверял его, так что в нем может быть множество опечаток. Но это не суть важно. Важно увидеть, как этот код выглядет вцелом.
Итак, это один язык программирования в языке С++.
А, вот, второй язык пррограммирования в языке С++!
#include <iostream>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <functional>
template <typename Container>
struct replace_zero: std::unary_function<Container, void>
{
void operator ()( Container &c ) const
{
int n = std::count_if( std::begin( c ), std::end( c ),
std::bind2nd( std::not_equal_to<int>(), 0 ) );
if ( n )
{
std::replace( std::begin( c ), std::end( c ), 0,
std::accumulate( std::begin( c ), std::end( c ), 0 ) / n );
}
}
};
int main()
{
int a[][14] = { { 1, 0, 3, 4, 0, 0, 7, 3, 0, 9, 5, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 7, 5, 0, 0, 0, 11, 1, 4, 0, 2, 0, 0, 1, 9 } };
for ( auto it = std::begin( a ); it != std::end( a ); ++it )
{
std::copy ( std::begin( *it ), std::end( *it ),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
}
std::cout << std::endl;
std::for_each( std::begin( a ), std::end( a ), replace_zero<decltype( a[0] )>() );
for ( auto it = std::begin( a ); it != std::end( a ); ++it )
{
std::copy ( std::begin( *it ), std::end( *it ),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
}
std::cout << std::endl;
return ( 0 );
}
Соверршенно два разных языка, не так ли?!
Более того во втором варианте я мог бы написать вместо предложения
for ( auto it = std::begin( a ); it != std::end( a ); ++it )
следующую конструкцию, если бы MS VC++ 2010 ее поддерживал ( я использовал этот компилятор для второго варианта)
for ( const auto &it : a )
Также хочу обратить внимание, что сначала у меня было записано в одном предложении таким образом
std::for_each( std::begin( a ), std::end( a ), replace_zero<decltype( char[14])>() );
но затем я его поменял на предложение с
decltype:
std::for_each( std::begin( a ), std::end( a ), replace_zero<decltype( a[0] )>() );
Как видите, между первым и вторым вариантом существует огромная пропасть! Теперь время изучения С++ значительно увеличивается. А я вспоминаю те времена, когда использовались Clipper Summer 85, Dbase III и т.д. Тогда мой один знакомый программист хвастался: "Я этот С++ за один вечер выучил!"