C ++如何遍历可变参数模板类型并将其添加到元组?

时间:2020-03-14 02:29:44

标签: c++ c++17 variadic-templates stdtuple fold-expression

这是一个相当复杂的项目,所以我自己无法解决。

这是相关代码,我将在后面详细解释。

#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;
  1. std :: get / std :: tuple_element需要constexpr索引参数,因此我无法遍历元组类型。

1 个答案:

答案 0 :(得分:0)

第一点:如L.F.所述,您将在tuple中分配的GetPropTuples()的大小设置为FirstPropTypeprops的数目。如果以下类型的元素数更大怎么办?

    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...>{}); }