среда, 19 января 2011 г.

and then in C++

Невеяно вот этим постом. Поскольку на том форуме темы частенько бегают с места на место, а некоторые вообще публично становятся не доступны, продублирую суть здесь:

В Оберон (точнее в один из его диалектов), где, как известно нет исключений и подобных механизмов, предлагается ввести новую синтаксическую конструкцию :
Первый_этап;
IF первый этап удался THEN
  Второй_этап
AND второй этап удался THEN
  Третий_этап
AND третий этап удался THEN
  Завершающие действия
ELSE
  Задача не выполнена
END
 Соотвественно если нам нужно определить на каком этапе случилась ошибка, то пишется это так:
step := 1;
Первый_этап;
IF первый этап удался THEN
  step := 2;
  Второй этап;
AND второй этап удался THEN
  ...
ELSE
  Log.String("Ошибка на этапе "); Log.Int(step)
END
 Но это конечно трубует менять язык. Соответственно менять компилятор. Что не здорово, лень и вообще не факт что кто-то будет делать.

Однако в С++ мы иногда тоже не можем пользоваться исключениями. Ну, например если мы от них намерянно отказались (см. например Google C++ Style). Менять компилятор С++ тоже совсем не интересно, но это и не нужно. Всё вышеперечисленное легко реализуется средствами самого языка, при чем без шаблонов и прочего метапрограммирования.

Нам достаточно того, что в С++ есть оператор запятая (,) и есть ленивые вычисления. Соответственно концепт такой:
bool r = (
    A1, // первый этап
    A2,
    A3,
первый_этап_удался ) and (
    B1, // второй этап
    B2, 
    B3,
второй_этап_удался ) and (
    C1, // третий этап
    C2, 
    C3,
третий_этап_удался ) and (
    Z1, // завершаюшие действия
    Z2,
    Z3,
true ) or (
    ERR1, // Задача не выполнена
    ERR2, 
    ERR3,
false);
 Ну и, как обычно, рабочий пример:
#include <iostream>

bool zoo(int c)
{
    int z = c;
    int step = 1;
    
    bool r = (
        step = 1,
        z--,
        std::cout << "step 1: " << z << std::endl,
    z > 0 ) and (
        step = 2,
        z-- ,
        std::cout << "step 2: " << z << std::endl,
    z > 0 ) and (
        step = 3,
        z--,
        std::cout << "step 3: " << z << std::endl,
    z > 0 ) and (
        z = z*z,
        std::cout << "Ending... " << z << std::endl,
    true ) or (
        std::cout << "Error on step " << step << std::endl,
    false );
    
    return r;
}

int main() 
{
    zoo(4);
    zoo(3);
    zoo(2);
    zoo(1);
    zoo(0);
}
Соответственно результат запуска такой:
step 1: 3
step 2: 2
step 3: 1
Ending... 1

step 1: 2
step 2: 1
step 3: 0
Error on step 3

step 1: 1
step 2: 0
Error on step 2

step 1: 0
Error on step 1

step 1: -1
Error on step 1