if (expected != actual)
error_msg({"functionX", expected, actual});
else
error_msg({"functionX", "okay"});
Здесь той же функции error_msg()
передаются при первом вызове три значения, а при втором — два.
У функции с параметром initializer_list
могут быть также и другие параметры. Например, у нашей системы отладки мог бы быть класс ErrCode
, представляющий различные виды ошибок. Мы можем пересмотреть свою программу так, чтобы в дополнение к списку initializer_list
передавать параметр типа ErrCode
следующим образом:
void error_msg(ErrCode е, initializer_list
cout << e.msg() << ": ";
for (const auto &elem : il)
cout << elem << " ";
cout << endl;
}
Поскольку класс initializer_list
имеет члены begin()
и end()
, мы можем использовать для обработки элементов серийный оператор for
(см. раздел 5.4.3). Эта программа, как и предыдущая версия, перебирает элементы заключенного в фигурные скобки списка значений, переданных параметру il
.
Для этой версии необходимо пересмотреть вызовы так, чтобы передать аргумент типа ErrCode
:
if (expected != actual)
error_msg(ErrCode(42), {"functionX", expected, actual});
else
error_msg(ErrCode(0), {"functionX", "okay"});
Параметры в виде многоточия предоставляются языком С++ для взаимодействия программам с кодом на языке С, использующим такое средство библиотеки С, как varargs
. В других целях параметр в виде многоточия не следует использовать. Использование varargs
описано в документации компилятора С.
Параметр в виде многоточия может быть только последним элементом в списке параметров и может принять любую из двух форм:
void foo(parm_list, ...);
void foo(...);
Первая форма определяет тип (типы) для нескольких параметров функции foo()
. Контроль типов аргументов, соответствующих определенным параметрам, осуществляется как обычно. Для аргументов, соответствующих параметру в виде многоточия, никакого контроля типов нет. В первой форме запятая после объявления параметра необязательна.
Упражнение 6.27. Напишите функцию, получающую параметр типа initializer_list
и возвращающую сумму элементов списка.
Упражнение 6.28. Во второй версии функции error_msg()
, где у нее есть параметр типа ErrCode
, каков тип элемента в цикле for
?
Упражнение 6.29. При использовании типа initializer_list
в серийном операторе for
использовали бы вы ссылку как управляющую переменную цикла? Объясните почему.
6.3. Типы возвращаемого значения и оператор return
Оператор return
завершает выполнение функции и возвращает управление той функции, которая вызвала текущую. Существуют две формы оператора return:
return
;
return
Оператор return
без значения применим только в такой функции, типом возвращаемого значения которой объявлен void
. Функции, возвращаемым типом которых объявлен void
, необязательно должны содержать оператор return
. В функции типа void
оператор return
неявно размещается после последнего оператора.
Как правило, функции типа void
используют оператор return
для преждевременного завершения выполнения. Это аналогично использованию оператора break
(см. раздел 5.5.1) для выход из цикла. Например, можно написать функцию swap()
, которая не делает ничего, если значения идентичны:
void swap(int &v1, int &v2) {
//
if (v1 == v2)
return;
//
int tmp = v2;
v2 = v1;
v1 = tmp;
//
}
Сначала эта функция проверяет, не равны ли значения, и если это так, то завершает работу. Если значения не равны, функция меняет их местами. После последнего оператора присвоения осуществляется неявный выход из функции.