【问题标题】:C++ how to iterate through variadic template types and add them to tuple?C ++如何遍历可变参数模板类型并将它们添加到元组?
【发布时间】:2020-03-14 02:29:44
【问题描述】:

这个比较复杂,所以一直没能自己解决。

这里是相关代码,后面我会更深入的解释。

#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 索引参数,因此我无法遍历元组类型。

【问题讨论】:

  • 此问题中显示的代码无法满足 stackoverflow.com 对 minimal reproducible example 的要求,这使得任何人几乎不可能自己尝试不同的方法以确保他们来提出一个可行的解决方案。这个问题必须是edited 以显示一个最小示例,不超过一两页代码(“最小”部分),任何人都可以剪切/粘贴、编译、运行和重现所描述的问题(“可重现”部分)完全如图所示。请参阅How to Ask 了解更多信息。
  • @SamVarshavchik 我编辑了代码以使其可重现:)
  • 是否有理由使用std::shared_ptr 而不是std::unique_ptr 与非拥有指针?据我所知,PropManager 拥有Props,因此似乎没有任何理由共享所有权。另外,您能解释一下GetPropTuples 的用途吗?我已经读了很多遍了,但我仍然不确定。我认为您正在寻找的可能是std::index_sequence。代码中有一些奇怪的东西。你能解释一下PropManager 的用途吗?有了这些信息,有人可能能够设计出更简单的东西。
  • 不同道具的数量不一致怎么办?例如,如果我们有 1 个First、2 个Seconds 和 3 个Thirds,你会返回什么?
  • @L.F.为了简单起见,我尝试不包含任何与确定哪些 prop 元组重叠相关的代码,但这应该不是问题

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


【解决方案1】:

第一点:正如L.F.所指出的,您将GetPropTuples()中分配的tuple的大小设置为propsFirstPropType的数量。如果以下类型的元素个数比较大呢?

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-06
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 2023-02-05
    • 1970-01-01
    相关资源
    最近更新 更多