Для примера вернемся к функции error_msg
из раздел 6.2.6. Эта функция получала переменное количество строковых аргументов и выводило сообщение об ошибке, составленное из переданных строк. Теперь вместо вызова функции error_msg()
мы возвратим вектор, содержащий строки сообщений об ошибке:
vector
// ...
// expected и actual - строки
if (expected.empty())
return {}; // возвратить пустой вектор
else if (expected == actual)
return {"functionX", "okay"}; //
//
else
return {"functionX", expected, actual};
}
В первом операторе return
возвращается пустой список. В данном случае возвращенный обработанный вектор будет пуст. В противном случае возвращается вектор, инициализированный двумя или тремя элементами, в зависимости от того, равны ли expected
и actual
.
У функции, возвращающей встроенный тип, заключенный в скобки список может содержать хотя бы одно значение, и это значение не должно требовать сужающего преобразования (см. раздел 2.2.1). Если функция возвращает тип класса, то используемые инициализаторы определяет сам класс (см. раздел 3.3.1).
main()
Есть одно исключение из правила, согласно которому функция с типом возвращаемого значения, отличного от void
, обязана возвратить значение: функция main()
может завершить работу без возвращения значения. Если процесс выполнения достигает конца функции main()
и нет никакого значения для возвращения, компилятор неявно добавляет возвращение значения 0.
Как упоминалось в разделе 1.1, значение, возвращаемое из функции main()
, рассматривается как индикатор состояния. Возвращение нулевого значения означает успех; большинство других значений — неудачу. У значения, отличного от нуля, есть машинно-зависимое значение. Чтобы сделать его независимым от машины, заголовок cstdlib
определяет две переменные препроцессора (см. раздел 2.3.2), которые можно использовать для индикации успеха или отказа:
int main() {
if (some failure)
return EXIT_FAILURE; //
else
return EXIT_SUCCESS; //
}
Поскольку это переменные препроцессора, им не должна предшествовать часть std::
и их нельзя использовать в объявлениях using
.
Функция, которая вызывает себя прямо или косвенно, является
//
int factorial(int val) {
if (val > 1)
return factorial(val-1) * val;
return 1;
}
В этой реализации осуществляется рекурсивный вызов функции factorial()
, чтобы вычислить факториал числа, начиная со значения, первоначально переданного val
, и далее в обратном порядке. Когда значение val
достигнет 1
, рекурсия останавливается и возвращается значение 1
.
В рекурсивной функции всегда должно быть определено factorial()
условием выхода является равенство значения параметра val
единице.
Ниже приведена трассировка выполнения функции factorial()
при передаче ей значения 5.
Трассировка вызова функции factorial(5)
Вызов | Возвращает | Значение |
---|---|---|
factorial(5) | factorial(4) * 5 | 120 |
factorial(4) | factorial(3) * 4 | 24 |
factorial(3) | factorial(2) * 3 | 6 |
factorial(2) | factorial(1) * 2 | 2 |
factorial(1) | 1 | 1 |
main()
Упражнение 6.30. Откомпилируйте версию функции str_subrange()
, представленной в начале раздела, и посмотрите, что ваш компилятор делает с указанными сообщениями об ошибках.