Я работаю над конвейерным шаблоном проектирования. Одна из моих целей проектирования - обеспечить динамическое связывание сегментов конвейера, предоставляя указатели на функции членов определенного класса данных.Заполните вектор с указателями на частично специализированные члены функции автоматически
Каждый из классов данных имеет набор членов функции (представляющих выходные порты класса данных), индексированные с использованием целочисленного аргумента шаблона. Эти функции динамически выводят тип возвращаемого значения с помощью ключевого слова auto
, но все принимают один и тот же аргумент целых чисел c_Idx
, то есть template <int N> auto getOutput(int c_Idx) const
. Функциональность, связанная с каждой функцией getOutput
, определяется (пользователем) в наборе частично специализированных структур getOutputImpl
. Таким образом, каждый класс данных может иметь от 1 до некоторого фиксированного номера K
портов выходных данных.
Для обеспечения динамической связи между сегментами трубопровода общим образом они могут храниться в контейнере std::vector<boost::any>
. Тем не менее, я должен иметь возможность заполнить этот вектор с помощью указателей на шаблоны членов функции автоматически.
Примера ручного осуществления показана ниже
template<class TLeafType>
class AlgorithmOutput
{
protected:
std::vector<boost::any> OutputPorts;
public:
AlgorithmOutput()
{
//////////////////////////////////////////
// This procedure needs to be automated //
//////////////////////////////////////////
std::function<std::unique_ptr<double>(int)> pOutFun1 = std::bind(
std::mem_fn(
true ? &AlgorithmOutput<TLeafType>::getOutput<0> : nullptr
),
this,
std::placeholders::_1
);
OutputPorts.push_back(pOutFun1);
std::function<std::unique_ptr<int>(int)> pOutFun2 = std::bind(
std::mem_fn(
true ? &AlgorithmOutput<TLeafType>::getOutput<1> : nullptr
),
this,
std::placeholders::_1
);
OutputPorts.push_back(pOutFun2);
}
virtual ~AlgorithmOutput() {}
protected:
TLeafType* asLeaf(void)
{
return static_cast<TLeafType*>(this);
}
TLeafType const* asLeaf(void) const
{
return static_cast<TLeafType const*>(this);
}
public:
template <int N>
auto getOutput(int c_Idx) const
{
return asLeaf() -> getOutput<N>(c_Idx);
}
boost::any getOutputPort(int PortIdx)
{
return OutputPorts[PortIdx];
}
};
class PipeOutputClass: public AlgorithmOutput<PipeOutputClass>
{
public:
template <int N>
auto getOutput(int c_Idx) const
{
return getOutputImpl<N>::apply(this, c_Idx);
}
template<int N, typename S> friend struct getOutputImpl;
template<int N, typename = void>
struct getOutputImpl
{
static auto apply(
PipeOutputClass const* p_Self,
int c_Idx
)
{ throw std::runtime_error("Wrong template argument."); }
};
template <typename S>
struct getOutputImpl<0, S>
{
static std::unique_ptr<double> apply(
PipeOutputClass const* p_Self,
int c_Idx
)
{
std::unique_ptr<double> mydouble(new double(10));
return mydouble;
}
};
template <typename S>
struct getOutputImpl<1, S>
{
static std::unique_ptr<int > apply(
PipeOutputClass const* p_Self,
int c_Idx
)
{
std::unique_ptr<int > myint(new int(3));
return myint;
}
};
};
Проблема с приведенным выше примером является то, что я определить функцию-члена указателей pOutFunX
вручную, в то время как я хотел бы автоматизировать эту процедуру.
Обратите внимание, что я не рассматриваю дизайнерские решения, которые значительно отличаются от дизайна, указанного выше.
Здесь я расскажу о некоторых возможных подходах к решению этой проблемы. Я разработал план решения, которое я в настоящее время рассматриваю, что может быть полезным, если вы попытаетесь ответить на этот вопрос:
- Получить номер определенного пользователя частично специализированные структуры, названные
getOutputImpl
. - Для каждой такой структуры определяют выходной тип своего элемента с именем
apply
. - Настройте (рекурсивную) мета-шаблонную процедуру, которая создает указатели на функции с соответствующей сигнатурой и добавляет их в вектор
OutputPort
.
Я бы предположил, что шаги 1-3 выше должны быть выполнены во время компиляции. Меня не интересует эстетика решения, если это не требует вмешательства пользователя, разрабатывающего классы вывода данных. Однако я бы предпочел не использовать собственные макросы компилятора.
Это сообщение показывает, как можно infer a member function signature, что может быть полезно.
Какова цель этого условного выражения? «правда? & AlgorithmOutput :: getOutput <0>: nullptr' –
dyp