Могу ли я представить рекурсивное решение 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
Мне нравится его простота.
Вам следует попробовать boost :: exception
Цель Boost Exception - упростить разработку иерархий классов исключений и помочь в написании кода обработки исключений и отчетов об ошибках.
Он поддерживает передачу произвольных данных на место улова, что в противном случае сложно из-за требований отсутствия бросков (15.5.1) для типов исключений. Данные могут быть добавлены к любому объекту исключения, либо непосредственно в throw-выражении (15.1), либо позже, когда объект исключения распространяется по стеку вызовов.
Возможность добавлять данные к объектам исключений после того, как они были переданы для выброса, важна, потому что часто некоторая информация, необходимая для обработки исключения, недоступна в контексте, где обнаружен сбой.
Boost Exception также поддерживает копирование объектов исключений в стиле N2179, реализованное незаметно и автоматически с помощью функции boost :: throw_exception.
Мне было интересно, может быть, было бы лучше использовать множественное наследование для наследования от каждого производного 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
. Но тогда в этом не было необходимости, поэтому мне и в голову не приходило.
exc_impl
. Но тогда в этом не было необходимости, поэтому мне и в голову не приходило. исключение (или любой другой класс в иерархии исключений std lib, переданный как необязательный параметр шаблона), поскольку он никогда не является производным от любого другого экземпляра exc_impl
. Но тогда в этом не было необходимости, поэтому мне и в голову не приходило.