Я строю сложную расширяемую систему. Детали не важны, но мне действительно нравится дизайн, за исключением этого вопроса.
У меня есть интерфейс WithState<T> : Subject
для некоторого типа T.
Проблемный класс настроен на template <typename... StateTypes>
.
Он содержит std::tuple<std::shared_ptr<WithState<StateTypes>>...>>
.
У меня есть функция std::any getStateFor(std::shared_ptr<Subject>)
(где WithState<T> : Subject
).
У меня также есть функция void handleStates(StateTypes... states)
(возможно, какдавайте возьмем кортеж на этом этапе, что бы ни было проще)
Теперь мне нужно соединить все эти части вместе: мне нужно выгрузить элементы в моем кортеже до shared_ptr<Subject>
, затем применить getStateFor
к каждому изэти элементы по порядку и std::any_cast
результаты в порядке StateTypes...
, а затем пересылают все это сразу как пакет параметров в handleStates
.
(Раньше это обозначалось как проблема XY: более высокие уровни абстракций не заботятся о конкретных типах состояний, тогда как я хочу реализовать нижние части с максимально возможной безопасностью типов. Пока что этот подходвыглядит хорошо для моих нужд)
Я мог бы сделать это, преобразовав свой кортеж в вектор, применив getStateFor
к каждому, затем написав рекурсивную функцию, которая применяет правильные any_cast
, но затем ядо сих пор не знаю, как собрать мои результаты в кортеж с различными типами. Интересно, работает ли это с умным выражением сгиба ...
Вот скелет существующего кода:
#include <memory>
#include <tuple>
#include <any>
#include <iostream>
#include <cassert>
#include <functional>
// ignoring references and const for brevity
class Subject {
public:
/* deleted copy assignment and constructor */
// this is here so that the example works
virtual std::any getState() = 0;
};
template <typename T> class WithState : public Subject { };
template <typename... StateTypes>
class StateHandler {
public:
std::tuple<std::shared_ptr<WithState<StateTypes>>...> subjects;
// this one is actually in another class, but it doesn't matter
void handleStates(StateTypes... states);
void handleStatesForSubjects(std::function<std::any (std::shared_ptr<Subject>)> getStateFor) {
// how do I implement this?
}
};
int main() {
struct foo { int a; int b; };
struct WithInt : public WithState<int> {
std::any getState() override { return 17; }
};
struct WithFoo : public WithState<foo> {
std::any getState() override { return foo { 1, 2 }; }
};
StateHandler<int, foo> handler;
handler.subjects = {
std::make_shared<WithInt>(), std::make_shared<WithFoo>() };
handler.handleStatesForSubjects([](auto subj) { return subj->getState(); });
}
на Godbolt
Тем не менее, до сих пор не хватает std::any_cast
s для конкретных типов.
Есть идеи?