C ++, как перебирать типы шаблонов variadi c и добавлять их в кортеж? - PullRequest
0 голосов
/ 14 марта 2020

Этот довольно сложный, поэтому я не смог решить его сам.

Вот соответствующий код, я объясню более подробно после.

#include <memory>
#include <vector>
#include <tuple>
#include <typeinfo>
#include <iostream>

struct Prop
{
    virtual ~Prop() {};
};

struct First : Prop
{
    int a;
};

struct Second : Prop
{
    int b;
};

struct Third : Prop 
{
    int c;
};


class PropManager
{
public:
    template<typename PropType>
    static std::shared_ptr<PropType> AddProp()
    {
        auto prop = std::make_shared<PropType>();
        props.push_back(prop);
        return prop;
    }

    static std::vector<std::shared_ptr<Prop>> props;

    template <typename PropType>
    static std::vector<std::shared_ptr<PropType>> GetProps()
    {
        std::vector<std::shared_ptr<PropType>> propTypes;
        for (std::shared_ptr<Prop> prop : props)
        {
            if (!prop) continue;
            if (typeid(PropType) == typeid( *prop.get() ) )
            {
                propTypes.push_back(std::static_pointer_cast<PropType>(prop));
            }
        }
        return propTypes;
    }

private:
    template <typename NthPropType, typename ...RemainingPropTypes>
    static void
    RecurseFillPropTuples
    (
        std::vector<std::tuple<std::shared_ptr<NthPropType>, std::shared_ptr<RemainingPropTypes>... >>* tuples,
        std::size_t recurse_count
    )
    {
        auto props = GetProps<NthPropType>();
        int i = 0;
        for (std::shared_ptr<NthPropType> prop : props)
        {
            std::get<recurse_count>( (*tuples)[i] ) = prop;
            i++;
        }
        if (sizeof...(RemainingPropTypes) > 0) {
            RecurseFillPropTuples<RemainingPropTypes...>(tuples, recurse_count + 1);
        }
    }

public:
    template <typename FirstPropType, typename ...NextPropTypes>
    static std::vector<std::tuple<std::shared_ptr<FirstPropType>, std::shared_ptr<NextPropTypes>... >>*
    GetPropTuples
    (
        std::vector<std::tuple<std::shared_ptr<FirstPropType>, std::shared_ptr<NextPropTypes>... >>* tuples = nullptr,
        std::size_t recurse_count = 0
    )
    {
        auto firstPropVector = GetProps<FirstPropType>();
        tuples = new std::vector<std::tuple<std::shared_ptr<FirstPropType>, std::shared_ptr<NextPropTypes>... >>(firstPropVector.size());

        int i = 0;
        for (std::shared_ptr<FirstPropType> prop : firstPropVector)
        {
            std::get<0>((*tuples)[i]) = prop;
            i++;
        }

        if (sizeof...(NextPropTypes) > 0)
        {
            PropManager::RecurseFillPropTuples<FirstPropType, NextPropTypes...>(tuples, recurse_count + 1);
        }
        return tuples;
    }
};

std::vector<std::shared_ptr<Prop>> PropManager::props = {};

int main()
{
    PropManager::AddProp<First>();
    PropManager::AddProp<Second>();
    PropManager::AddProp<Third>();

    PropManager::GetPropTuples<First, Second, Third>();
}

В конечном счете, мое желание - вернуть вектор кортежей шаблонных типов. Здесь на самом деле возникают две связанные проблемы:

PropManager::RecurseFillPropTuples<FirstPropType, NextPropTypes...>(tuples, recurse_count + 1);
  1. Мне нужно пропустить все типы, а не сворачивать, потому что кортежи аргументов требуют, чтобы все типы были известны при каждом вызове рекурсии
std::get<recurse_count>( (*tuples)[i] ) = prop;
std :: get / std :: tuple_element требуется параметр индекса constexpr, поэтому я не могу перебирать типы кортежей.

1 Ответ

0 голосов
/ 14 марта 2020

Первая точка: как указано LF, вы устанавливаете размер tuple, выделенный в GetPropTuples(), как число FirstPropType в props. Что если число элементов следующих типов больше?

    auto firstPropVector = GetProps<FirstPropType>();
    tuples = new std::vector<std::tuple<std::shared_ptr<FirstPropType>, std::shared_ptr<NextPropTypes>... >>(firstPropVector.size());

Учитывая, что я оставляю эту проблему нерешенной, я предлагаю вам избежать рекурсии и, учитывая, что вы пометили C ++ 17, использование сворачивания.

Другое предложение: используйте auto, когда это возможно.

Таким образом, с учетом вспомогательной функции, которая устанавливает значения, с учетом типа и соответствующего индекса

  template <std::size_t I, typename PType, typename VType>
  static void SetTuples (VType * pv)
   {
     std::size_t ind{};

     for ( auto prop : GetProps<PType>() )
        std::get<I>( (*pv)[ind++] ) = prop;
   }

вам, по существу, нужна только индексная последовательность, поэтому

  template <typename ... PTypes, std::size_t ... Is>
  static auto GetPropTuples (std::index_sequence<Is...>)
   {
     using RetType
        = std::vector<std::tuple<std::shared_ptr<PTypes>...>>;

     auto tuples = new RetType(1u); // <<--- set the correct size!!!

     (SetTuples<Is, PTypes>(tuples), ...);

     return tuples;
   }

  template <typename ... PTypes>
  static auto GetPropTuples ()
   { return GetPropTuples<PTypes...>
        (std::index_sequence_for<PTypes...>{}); }
...