printУлучшения языка C

printФункции и операции

Функциям, выполняющим одинаковые действия с данными различных типов, в С++ можно дать одинаковые имена. Компилятор сможет определить, какую функцию из набора вызвать, по типу аргументов.
void print(int x)
{ printf("%d",x);
}
void print(char x)
{ printf("%c",x);
}
int main()
{
  print(10);
  print('A');
}
Чтобы на этапе компоновки программы можно было установить соответствие между функциями и их вызовами в имя функции на языке С++ включаются типы ее параметров. Для функций на языке С типы параметров не важны, поэтому перед объявлением функции из библиотек на языке С нужно написать extern "C".
Обычно один и тот же заголовочный файл используется для программ на С и С++, поэтому в него добавляет следующие строки:
#ifdef __cplusplus
extern "C" {
#endif
// объявления функций на С
#ifdef __cplusplus
}
#endif
Вместо определения набора функций, отличающихся только количеством параметров, можно указать при объявлении функции в заголовочном файле значения по умолчанию для некоторых параметров. Эти параметры должны быть последними в списке. Если при вызове соответствующий аргумент пропущен, то должны быть пропущены и все аргументы за ним. В качестве значений по умолчанию можно использовать константы и глобальные переменные.
void f(int a, int n=100, double eps=1e-9);
...
f(1,200,1e-6);
f(1,200); // f(1,200,1e-9);
f(1); // f(1,100,1e-9);
В C++ можно переопределять операции для собственных типов данных и, также как для функций, нужный вариант операции будет вызван в зависимости от типов аргументов. Разработчиками языка эта возможность была использована, чтобы избавиться от проблемы несоответствия форматов и списка аргументов в функциях форматированного ввода-вывода. При изменении типа переменной в программе на С необходимо было отследить все появления этой переменной в списке аргументов в printf/scanf и изменить строки с форматами.
int a,b;
scanf("%d%d",&a,&b);
В С++ для ввода-вывода были переопределены операции << и >> (в С это операции поразрядного сдвига для целых чисел). Первым аргументом операции указывается поток ввода (например, cin – консольный ввод, console input) или поток вывода (например, cout – консольный вывод, console output), а вторым аргументом – вводимая переменная или выводимое значение. В качестве результата операция возвращает поток и поэтому её можно применить последовательно для ввода или вывода нескольких значений.
int a,b;
cin>>a>>b; 
cout<<"a="<<a<<" b="<<b<<"\n";
Обратите внимание на отсутствие форматов и операции &, так как в операции ввода происходит передача аргумента по ссылке.
Запомнить: направление уголков указывает направление передачи информации.

Лямбда-выражения и анонимные функции можно использовать везде, где требуется передавать в качестве аргумента функцию.
Лямбда-выражения создаются следующим образом:
[замыкание](параметры){ return выражение; }
Тип лямбда-выражения определяется по типу возвращаемого значения.

vector<int> v;
// подсчитать количество положительных элементов вектора v
// через обычную функцию
int gt(int x){ return x>0; }
...
int n=count_if(v.begin(),v.end(),gt); // больше чего?
// через лямбда-выражение
int n=count_if(v.begin(),v.end(),[](int x){ return x>0; });

Анонимные функции создаются аналогичным образом, но нужно указать тип результата и можно писать любые операторы в теле функции:
[замыкание](параметры) –> тип_результата { операторы }

В замыкании нужно указать список имен объектов, которые используются для вычислений, но не передаются как параметры. Перед именем объекта можно указать &, если объект нужно передавать по ссылке, иначе в замыкании будет копия значения объекта в момент определения лямбда-выражения. Можно не перечислять самостоятельно объекты поименно, а указать [=], если все объекты должны храниться по значению, или [&] для передачи по ссылке. Важно: лямбда-выражение, использующее в замыкании ссылки на локальные объекты блока, становится ошибочным после завершения блока, так как объекты будут уничтожены. При использовании в замыкании копий значений, лямбда-выражение останется корректным. Можно поместить в замыкание любое значение и дать ему имя.

int i=0;
// заполнить вектор квадратами натуральных чисел
generate(v.begin(),v.end(),[&i]()->int { ++i; return i*i; });
auto one = [value=1](){return value;};
cout<<one(); // выводится 1

Альтернативный синтаксис можно использовать при определении обычных функций. Такой синтаксис особенно полезен для шаблонов функций, когда тип результата определить затруднительно.
auto f(int x) -> int;
template <typename T1, typename T2>
auto add(const T1 &a, const T2 &b) -> decltype(a+b)
{ return a+b;
}
loading