This one is rather complex, so I haven't been able to solve it myself.
Here's the relevant code, I'll explain more in depth after.
#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>();
}
Ultimately, my desire is to return a vector of tuples of templated types. There are actually two related problems going on here.
PropManager::RecurseFillPropTuples<FirstPropType, NextPropTypes...>(tuples, recurse_count + 1);
std::get<recurse_count>( (*tuples)[i] ) = prop;
First point: as pointed by LF, you set the size of the tuple
allocated in GetPropTuples()
as the number of FirstPropType
in props
. What if the number of elements of the following types is bigger?
auto firstPropVector = GetProps<FirstPropType>();
tuples = new std::vector<std::tuple<std::shared_ptr<FirstPropType>, std::shared_ptr<NextPropTypes>... >>(firstPropVector.size());
Given that I leave this problem unresolved, I suggest you to avoid recursion and, given that you've tagged C++17, the use of folding.
Other suggestion: use auto
when possible.
So, given an helper function that set the values, given the type and the corresponding index
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;
}
you, substantially, only need a index sequence, so
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...>{}); }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.