Доступ к типу в шаблоне с переменным индексом
Я хотел бы получить тип в шаблоне variadic по индексу. Индекс указывается в качестве аргумента шаблона. Мне удалось найти "хак", который работает, но я считаю, что это не в духе вариационного шаблонного программирования. Кроме того, он использует дополнительную память.
Вот код с некоторыми пояснениями:
template <typename... InputPortTypes>
class PipelineReceiver
{
protected:
// This tuple is used for storing types only
// Hence, I would like to get rid of it, but I am not sure how.
std::tuple<
std::function<std::unique_ptr<InputPortTypes> (int)>...
> InputPortsTuple;
// This vector is used for storing the actual objects
// This is needed to be able to access/change its elements
// during run time later on.
// The vector is used for storage of function pointers (i.e. of type std::function)
// that represent methods of another object upstream the pipeline.
std::vector<boost::any> InputPortsVector;
public:
PipelineReceiver()
{
// create an empty vector of the required size
InputPortsVector.resize(sizeof...(InputPortTypes));
}
void connectPorts(int InputPortIndex, boost::any c_OutputPort)
{
// connect ports
InputPortsVector[InputPortIndex] = c_OutputPort;
}
// this function needs to be modified to avoid using InputPortsTuple
template<int N>
void getInputPortValue(void)
{
std::cout <<
*boost::any_cast<decltype(std::get<N>(this -> InputPortsTuple))>(
InputPortsVector[N]
)(0) <<
std::endl;
}
};
Я хотел бы удалить объект InputPortsTuple
и заменить его некоторой формой рекурсивной процедуры для вывода типов в getInputPortValue
,
В идеале хотелось бы N
быть динамическим параметром вместо аргумента шаблона. Однако я не уверен, возможно ли это.
2 ответа
Вы могли бы просто злоупотреблять std::tuple_element
:
typename std::tuple_element<N, std::tuple<InputPortTypes...>>::type
Примечание: если вы можете использовать C++14,
std::tuple_element_t<N, std::tuple<InputPortTypes...>>
это хороший способ сделать то же самое. Однако, не все распространенные компиляторы знают это.
Если вас устраивает создание собственного шаблона, вы можете создать свой вариантstd::tuple_element
который напрямую принимает список типов без необходимости оборачивать его вstd::tuple
.
#include <type_traits>
using std::size_t;
template<std::size_t N, class ...T>
struct typelist_element;
// recursive case
template<std::size_t N, class Head, class... Tail>
struct typelist_element<N, Head, Tail...> : typelist_element<N-1, Tail...>
{
static_assert(N < (sizeof...(Tail) + 1), "N out of bounds");
};
// base case
template<class Head, class... Tail >
struct typelist_element<0, Head, Tail...>
{
using type = Head;
};
// error out of bounds, only here to silence compiler warnings about undefined template
template<>
struct typelist_element<0>
{
using type = void;
};
template<std::size_t N, class ...T>
using typelist_element_t = typename typelist_element<N, T...>::type;
И тогда просто
boost::any_cast<typelist_element_t<N, InputPortTypes...>>(InputPortsVector[N])(0)
Примечание об эффективности: статическое утверждение будет оцениваться для каждой рекурсии, поэтому не самое лучшее его наличие.