Пользовательские исключения в C ++

Могу ли я представить рекурсивное решение Python для этой проблемы?

def choose_iter(elements, length):
    for i in xrange(len(elements)):
        if length == 1:
            yield (elements[i],)
        else:
            for next in choose_iter(elements[i+1:len(elements)], length-1):
                yield (elements[i],) + next
def choose(l, k):
    return list(choose_iter(l, k))

Пример использования:

>>> len(list(choose_iter("abcdefgh",3)))
56

Мне нравится его простота.

16
задан Matthew Murdoch 22 October 2009 в 08:46
поделиться

2 ответа

Вам следует попробовать boost :: exception

Цель Boost Exception - упростить разработку иерархий классов исключений и помочь в написании кода обработки исключений и отчетов об ошибках.

Он поддерживает передачу произвольных данных на место улова, что в противном случае сложно из-за требований отсутствия бросков (15.5.1) для типов исключений. Данные могут быть добавлены к любому объекту исключения, либо непосредственно в throw-выражении (15.1), либо позже, когда объект исключения распространяется по стеку вызовов.

Возможность добавлять данные к объектам исключений после того, как они были переданы для выброса, важна, потому что часто некоторая информация, необходимая для обработки исключения, недоступна в контексте, где обнаружен сбой.

Boost Exception также поддерживает копирование объектов исключений в стиле N2179, реализованное незаметно и автоматически с помощью функции boost :: throw_exception.

12
ответ дан fmuecke 22 October 2009 в 08:46
поделиться

Мне было интересно, может быть, было бы лучше использовать множественное наследование для наследования от каждого производного std: : классы исключений

Обратите внимание, что это проблема из-за того, что исключения в стандартной библиотеке не являются виртуальными производными друг от друга. Если вы введете множественное наследование, вы получите ужасную иерархию исключений ромба без виртуального наследования и не сможете перехватывать производные исключения с помощью std :: exception & , поскольку ваш производный класс исключений содержит два подобъекта std :: exception , что делает std :: exception «неоднозначным базовым классом».

Конкретный пример:

class my_exception : virtual public std::exception {
  // ...
};

class my_runtime_error : virtual public my_exception
                       , virtual public std::runtime_error {
  // ...
};

Теперь my_runtime_error дважды наследуется (косвенно) из std :: exception , один раз через std :: run_time_error и один раз через my_exception . Поскольку первый не является производным от std :: exception виртуально, этот

try {
  throw my_runtime_error(/*...*/);
} catch( const std::exception& x) {
  // ...
}

работать не будет.

Править:

Я думаю, что я видел первый пример иерархии классов исключений с участием MI в одной из книг Страуструпа, поэтому я пришел к выводу, что в целом это хорошая идея. То, что исключения std lib не являются производными друг от друга, я считаю ошибкой.

Когда я в последний раз разрабатывал иерархию исключений, я очень широко использовал MI, но не унаследовал от классов исключений std lib. В этой иерархии были абстрактные классы исключений, которые вы определили, чтобы ваши пользователи могли их поймать, и соответствующие классы реализации, полученный из этих абстрактных классов и из базового класса реализации, который вы фактически выбрасываете. Чтобы упростить задачу, я определил несколько шаблонов, которые сделают всю тяжелую работу:

// something.h
class some_class {
private:
  DEFINE_TAG(my_error1); // these basically define empty structs that are needed to 
  DEFINE_TAG(my_error2); // distinguish otherwise identical instances of the exception 
  DEFINE_TAG(my_error3); // templates from each other (see below)
public:
  typedef exc_interface<my_error1>  exc_my_error1;
  typedef exc_interface<my_error2>  exc_my_error2;
  typedef exc_interface<my_error3,my_error2> // derives from the latter
                                    exc_my_error3;

  some_class(int i);
  // ...
};

//something.cpp
namespace {
  typedef exc_impl<exc_my_error1> exc_impl_my_error1;
  typedef exc_impl<exc_my_error2> exc_impl_my_error2;
  typedef exc_impl<exc_my_error3> exc_impl_my_error3;
  typedef exc_impl<exc_my_error1,exc_my_error2> // implements both
                                  exc_impl_my_error12;
}
some_class::some_class(int i)
{
  if(i < 0) 
    throw exc_impl_my_error3( EXC_INFO  // passes '__FILE__', '__LINE__' etc.
                            , /* ... */ // more info on error
                            ); 
}

Оглядываясь назад, я думаю, что мог бы сделать этот шаблон класса exc_impl производным от std :: исключение (или любой другой класс в иерархии исключений std lib, переданный как необязательный параметр шаблона), поскольку он никогда не является производным от любого другого экземпляра exc_impl . Но тогда в этом не было необходимости, поэтому мне и в голову не приходило.

исключение (или любой другой класс в иерархии исключений std lib, переданный как необязательный параметр шаблона), поскольку он никогда не является производным от любого другого экземпляра exc_impl . Но тогда в этом не было необходимости, поэтому мне и в голову не приходило.

исключение (или любой другой класс в иерархии исключений std lib, переданный как необязательный параметр шаблона), поскольку он никогда не является производным от любого другого экземпляра exc_impl . Но тогда в этом не было необходимости, поэтому мне и в голову не приходило.

16
ответ дан 30 November 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: