скалярно-конвертирующий конструктор копирования для класса с аргументами, зависящими от типа - PullRequest
0 голосов
/ 10 мая 2019

Положение

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

Примером этого является класс, который просто переупорядочивает входные данные, или класс, который просто удаляет ненужные входные данные.

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

Идея - это конструктор, который принимает std::function формы вместе с размером входного и выходного вектора.

std::function<void(const Eigen::VectorBlock<const drake::VectorX<T>>&, Eigen::VectorBlock<drake::VectorX<T>>& )>;

«Функция преобразования» может быть реализована в этом функторе.

Пример использования: если бы я хотел преобразовать данные состояния 3D (x, y, z, roll, pitch, yaw) в данные состояния 2D (x, y, yaw), я мог бы просто написать функтор, такой как

void 3Dto2D(const Eigen::VectorBlock<const drake::VectorX<T>>& input, Eigen::VectorBlock<drake::VectorX<T>>& output)
{
    output[0] = input[0]; //x
    output[1] = input[1]; //y
    output[2] = input[5]; //yaw
    output[3] = input[6]; //x_dot
    output[4] = input[7]; //y_dot
    output[5] = input[11]; //yaw_dot
}

И передать этот функтор в этот «StateConverter».

Проблема

Проблема, с которой я сталкиваюсь, касается конструктора копий с преобразованием в скаляр. Как мне реализовать это, когда у класса есть специфичные для типа объекты-члены?

Основная часть этого класса выглядит следующим образом (для полноты)

using ConversionFunc = std::function<void(const Eigen::VectorBlock<const drake::VectorX<T>>&, Eigen::VectorBlock<drake::VectorX<T>>& )>;;

// Some black magic to handle alias explicit template instantiation

template <typename T>
StateConverter<T>::StateConverter(ConversionFunc func, const unsigned int input_size, const unsigned int output_size) :
    systems::LeafSystem<T>(systems::SystemTypeTag<StateConverter>{}),
    input_idx(this->DeclareVectorInputPort("input_port", systems::BasicVector<T>(input_size)).get_index()),
    output_idx(this->DeclareVectorOutputPort("output_port", systems::BasicVector<T>(output_size), &StateConverter::convert).get_index())
{
    convert_func = func;
}

template <typename T>
void StateConverter<T>::convert(const drake::systems::Context<T>& context, systems::BasicVector<T>* output) const
{
    const auto state = this->EvalVectorInput(context, input_idx)->get_value();
    auto mutable_output = output->get_mutable_value();
    convert_func(state, mutable_output);
}

1 Ответ

1 голос
/ 10 мая 2019

Частичное решение

Я закончил тем, что создал структуру, которая содержит все 3 обязательных экземпляра шаблонной функции

struct ConversionFunc
{
    std::function<void(const Eigen::VectorBlock<const drake::VectorX<double>>&, Eigen::VectorBlock<drake::VectorX<double>>& )> double_impl;
    std::function<void(const Eigen::VectorBlock<const drake::VectorX<drake::AutoDiffXd>>&, Eigen::VectorBlock<drake::VectorX<drake::AutoDiffXd>>& )> autodiff_impl;
    std::function<void(const Eigen::VectorBlock<const drake::VectorX<drake::symbolic::Expression>>&, Eigen::VectorBlock<drake::VectorX<drake::symbolic::Expression>>& )> symbolic_impl;
};

Что и передается в конструкторе копирования

Я создаю структуру следующим образом

template <typename T>
void convert_func(const Eigen::VectorBlock<const VectorX<T>>& state, Eigen::VectorBlock<VectorX<T>>& output)
{
    // Some example conversions
    output[0] = state[4];
    output[1] = state[6];
    output[2] = state[12];
    output[3] = state[14];
}

// I'm sure there's some way to automatically create these instantiations in the constructor of ConversionFunc...
ConversionFunc func;
func.double_impl = convert_func<double>;
func.autodiff_impl = convert_func<drake::AutoDiffXd>;
func.symbolic_impl = convert_func<drake::symbolic::Expression>;

И передайте это моему Converter следующим образом

auto converter = builder.AddSystem(std::make_unique<StateConverter<double>>(func, 16, 4));

Задача

К сожалению, этот метод вызывает утечку памяти, вызывая выброс std::bad_alloc ...

...