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

Бих искал да получа тип в променлив шаблон по индекс. Индексът е посочен като аргумент на шаблона. Успях да намеря „хак“, който работи, но вярвам, че не е в духа на програмирането с вариативни шаблони. Освен това използва допълнителна памет.

Ето кода с някои обяснения:

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