Доступ к типу в вариативном шаблоне по индексу

Я хотел бы получить тип в вариативном шаблоне по индексу. Индекс указывается в качестве аргумента шаблона. Мне удалось найти «хак», который работает, но я считаю, что он не в духе вариативного программирования шаблонов. Кроме того, он использует дополнительную память.

Вот код с некоторыми пояснениями:

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 был динамическим параметром, а не аргументом шаблона. Однако я не уверен, возможно ли это.


person Community    schedule 19.04.2015    source источник
comment
Вы можете тривиально удалить неиспользуемый элемент, используя std::declval<std::tuple<std::function<std::unique_ptr<InputPortTypes> (int)>...>>() вместо this->InputPortsTuple, если только я что-то не упустил. (Я знаю, что это не то, что вам действительно нужно. Это просто немного менее плохая альтернатива.)   -  person    schedule 19.04.2015
comment
Но на самом деле, почему бы вам просто не хранить элементы непосредственно в кортеже? Зачем вообще использовать вектор? Вы все еще можете изменить кортеж.   -  person    schedule 19.04.2015
comment
@hvd Спасибо за ваши комментарии. То, что вы предложили в первом комментарии, является лучшей альтернативой тому, что я делаю в данный момент, но, как вы указали, все еще не идеально. Я опубликую еще один комментарий, чтобы объяснить, почему мне нужно использовать вектор.   -  person    schedule 19.04.2015
comment
@hvd Что касается вашего второго комментария, я пытался объяснить, почему мне нужен вектор в комментарии, который идет перед определением вектора (т.е. «Этот (вектор) необходим для доступа к /изменить его элементы во время выполнения позже'). Я постараюсь улучшить комментарий, чтобы сделать его более понятным. Спасибо, что указали на это.   -  person    schedule 19.04.2015
comment
Да, я читал это, но я этого не вижу: кортеж также позволяет изменять свои элементы: std::get<N>(tuple) возвращает ссылку lvalue, которую вы можете назначить без каких-либо проблем.   -  person    schedule 19.04.2015
comment
@hvd Вы правы. Однако N должен быть аргументом времени компиляции. Меня беспокоит размер исполняемого файла и читабельность кода, если я начну злоупотреблять различными псевдодинамическими функциями, например. цикл по элементам кортежа.   -  person    schedule 19.04.2015
comment
Быстрый поиск показывает, что Boost.Fusion может это сделать, сохраняя при этом читабельность кода. И я думаю, что было бы хорошо измерить размер исполняемого файла: мои ожидания противоположны вашим, я ожидаю, что Boost.Any добавит много кода, который в конечном итоге не будет использоваться, поэтому, избегая Boost.Any, вы можете уменьшить код. размер. Но решать вам, конечно. Если вы считаете, что использование вектора улучшает читабельность, и вы тот, кто в конечном итоге поддерживает код, это очень веская причина для использования вектора. :)   -  person    schedule 19.04.2015
comment
@hvd Спасибо за ваш комментарий. Должен признаться, я никогда не слышал о Boost.Fusion, но я обязательно посмотрю на него позже. Что касается Boost.Any, есть и другие причины для его использования. Это связано с (неполным) решением другой проблемы, которую я не описал в этом вопросе.   -  person    schedule 19.04.2015


Ответы (1)


Вы можете просто злоупотреблять std::tuple_element:

typename std::tuple_element<N, std::tuple<InputPortTypes...>>::type

Примечание: если вы можете использовать C++14,

std::tuple_element_t<N, std::tuple<InputPortTypes...>>

это лучший способ сделать то же самое. Однако не все распространенные компиляторы об этом знают.

person Wintermute    schedule 19.04.2015
comment
Суффикс ::type в std::tuple_element_t не нужен. - person ; 19.04.2015
comment
@ligoore Спасибо. Глупая ошибка копирования и вставки. - person Wintermute; 19.04.2015
comment
@Wintermute Спасибо за ваш ответ. Если я правильно понял, вы предлагаете заменить decltype(std::get<N>(this -> InputPortsTuple)) на заранее объявленный тип std::tuple_element<N, std::tuple<InputPortTypes...>>::type. К сожалению, это не работает. Я получаю ошибку времени выполнения failed conversion using boost::any_cast. Имена, связанные с typeid переменных, объявленных через decltype(std::get‹N›(this -> InputPortsTuple)) и typename std::tuple_element<N, std::tuple<InputPortTypes...>>::type, также различаются. - person ; 19.04.2015
comment
Код в ответе даст вам n-й тип пакета аргументов InputPortTypes. Если я правильно прочитал ваш код, то вы хотите обернуть это в std::function<std::unique_ptr<T>(int)>, поэтому в конечном итоге вы ищете std::function<std::unique_ptr<typename std::tuple_element<N, std::tuple<InputPortTypes...>>::type>(int)> - person Wintermute; 19.04.2015
comment
@Wintermute, я должен извиниться. Я запутался в обозначениях и не заметил, что вы указали тип шаблона InputPortTypes. Спасибо за ваш ответ. - person ; 19.04.2015