Я заменяю ... около 6000 строк кода десериализации C на то, что, я надеюсь, составляет около 3000 строк C ++. Основной существующий шаблон выглядит так:
ser_ret_t msgpack_unpack_mystruct(msgpack_object *obj, mystruct_t *d, void *unused = NULL)
{
NEXT_WORK_OBJ(array, i, work_obj);
ret |= msgpack_unpack_line(work_obj, &d->line);
NEXT_WORK_OBJ(array, i, work_obj);
ret |= msgpack_unpack_node(work_obj, &d->leftNode);
//etc....
Это повторяется один раз для каждой переменной в данной структуре. array
, i
и work_obj
- все переменные состояния, используемые msgpack, а d
- указатель произвольной структуры. NEXT_WORK_OBJ
- макрос препроцессора, необходимый для настройки переменных состояния. msgpack_unpack_*
- это функция с произвольными параметрами.
Это не только многословно, но и неполно, поскольку базовый буфер продолжает обрабатываться даже в случае сбоя.
Моя мысль состоит в том, чтобы заменить переменные состояния классом состояния / помощника, при этом единственной проблемой является вызов произвольной функции внутри класса. Я справляюсь с этим, делая не вызов внутри класса, а через лямбду.
class UnpackHelper
{
public:
void GetNext(std::function<ser_ret_t(msgpack_object*)> callback)
{
//make sure it's safe to continue processing buffer.
if (m_status != SER_SUCCESS)
return;
NextObj();
m_status |= callback(m_pWork);
}
};
NextObj()
заменяет макрос препроцессора и корректирует внутренние переменные состояния класса. Теперь код клиента выглядит так:
ser_ret_t msgpack_unpack_mystruct(msgpack_object *obj, mystruct_t *d, void *unused = NULL)
{
UnpackHelper up;
up.GetNext([=](auto pWork) {return msgpack_unpack_line(pWork, &d->line); });
up.GetNext([=](auto pWork) {return msgpack_unpack_node(pWork, &d->leftNode);});
Мой вопрос конкретно о клиентском коде и лямбдах. Насколько я понимаю, здесь происходит default capture
, и я также понимаю, что это не рекомендуется. Поскольку захват всегда происходит на элементе указателя, переданного в функцию (d
), тем не менее, Я считаю, что этот шаблон безопасен. Это правильно? Учитывая тысячи лямбд, которые будут существовать, я бы хотел избежать ненужного многословия. Во-вторых, можно ли каким-либо образом сократить или удалить список параметров? (auto pWork)
довольно минимально, но ...
Мой новый, третий вопрос, основанный на изучении std::function
.. мой механизм обратного вызова вообще необходим? std::function
выглядит как то, что я мог бы использовать, чтобы создать произвольный вызов непосредственно в классе. В настоящее время я смотрю на принятый ответ здесь: C ++: передать функцию с произвольным числом параметров в качестве параметра , чтобы посмотреть, можно ли ее применить к моему коду ... без использования переменных аргументов в стиле C. Похоже, это может сработать, но ничего не покупает, кроме раздувания кода, вызванного расширением шаблона.