在 C++/Qt 中填充 QSharedPointer<T> 集合
Filling QSharedPointer<T> collection in C++/Qt
我使用 C++17、GCC 7.4.0、Qt 5。12.x。
我想使用通用函数(模板)从 QJsonArray
(序列化 Q_GADGETS
)实例中填充 QSharedPointer<T>
集合。所以,至少,QList 和 QVector 可以用它填充(我不是想找到高速方法)。假设我们有 T convert_func(const QJsonValue& value)
,它将 QJsonValue
转换为 T
实例。
for (const auto& json_value: qAsConst(json_array)){
auto ptr = QSharedPointer<T>::create(convert_func(json_value));
collection << ptr;
}
因此,函数模板必须接受包含 QSharedPointer(指向 Q_GADGETS 的智能指针)的典型 Qt 容器。如何实现?
伪代码:
QJsonArray json_array;
//...
//json_array has been filled
QVector<QSharedPointer<My_gadget>> gadget_vector = fill_gadgets<QVector<QSharedPointer<My_gadget>>>(json_array);
QList<QSharedPointer<My_gadget>> gadget_list = fill_gadgets<QList<QSharedPointer<My_gadget>>>(json_array);
//or like that (QSharedPointer is mandatory, that's why is implicit):
QVector<QSharedPointer<My_gadget>> gadget_vector = fill_gadgets<QVector,My_gadget>(json_array);
QList<QSharedPointer<My_gadget>> gadget_list = fill_gadgets<QList, My_gadget>(json_array);
您可以假设我们有 std::array
(或其他集合)而不是 QJsonArray
作为输入。问题在于使用模板描述输出集合。
如果您想从任何源容器 (ContSource) 转换到中间有一些智能指针的其他容器目标,以下代码片段应该可以完成工作。
它对 ContDest 和 ContSource 使用模板模板参数。如果您只使用 Qt 容器,则不需要它们的可变参数模板参数,因为它们仅由一个参数模板化,但如果您使用标准容器,则它们由类型和分配器模板化。因此,带有可变参数模板参数的代码可以很好地与示例所示的两者一起使用。
template < template <typename... Args> class ContDest,
template <typename... Args> class ContSource,
template<typename... Args> class SmartPointer,
typename E>
ContDest<SmartPointer<E>> fillGadget(const ContSource<E>& values)
{
ContDest<SmartPointer<E>> res;
for (const auto & val : values)
res.push_back(SmartPointer<E>(new E(val)));
return res;
}
const QList<int> vals = { 1,2,3 };
auto gadget_stdvector = fillGadget< std::vector, QList, std::shared_ptr, int >(vals);
std::deque<int> val2 = { 1 ,2, 3 };
auto gadget_qvector = fillGadget< QVector, std::deque, QSharedPointer, int >(val2);
请注意,对于连续存储源容器和目标容器值的所有情况,它都不是最佳选择。
我使用 C++17、GCC 7.4.0、Qt 5。12.x。
我想使用通用函数(模板)从 QJsonArray
(序列化 Q_GADGETS
)实例中填充 QSharedPointer<T>
集合。所以,至少,QList 和 QVector 可以用它填充(我不是想找到高速方法)。假设我们有 T convert_func(const QJsonValue& value)
,它将 QJsonValue
转换为 T
实例。
for (const auto& json_value: qAsConst(json_array)){
auto ptr = QSharedPointer<T>::create(convert_func(json_value));
collection << ptr;
}
因此,函数模板必须接受包含 QSharedPointer(指向 Q_GADGETS 的智能指针)的典型 Qt 容器。如何实现?
伪代码:
QJsonArray json_array;
//...
//json_array has been filled
QVector<QSharedPointer<My_gadget>> gadget_vector = fill_gadgets<QVector<QSharedPointer<My_gadget>>>(json_array);
QList<QSharedPointer<My_gadget>> gadget_list = fill_gadgets<QList<QSharedPointer<My_gadget>>>(json_array);
//or like that (QSharedPointer is mandatory, that's why is implicit):
QVector<QSharedPointer<My_gadget>> gadget_vector = fill_gadgets<QVector,My_gadget>(json_array);
QList<QSharedPointer<My_gadget>> gadget_list = fill_gadgets<QList, My_gadget>(json_array);
您可以假设我们有 std::array
(或其他集合)而不是 QJsonArray
作为输入。问题在于使用模板描述输出集合。
如果您想从任何源容器 (ContSource) 转换到中间有一些智能指针的其他容器目标,以下代码片段应该可以完成工作。
它对 ContDest 和 ContSource 使用模板模板参数。如果您只使用 Qt 容器,则不需要它们的可变参数模板参数,因为它们仅由一个参数模板化,但如果您使用标准容器,则它们由类型和分配器模板化。因此,带有可变参数模板参数的代码可以很好地与示例所示的两者一起使用。
template < template <typename... Args> class ContDest,
template <typename... Args> class ContSource,
template<typename... Args> class SmartPointer,
typename E>
ContDest<SmartPointer<E>> fillGadget(const ContSource<E>& values)
{
ContDest<SmartPointer<E>> res;
for (const auto & val : values)
res.push_back(SmartPointer<E>(new E(val)));
return res;
}
const QList<int> vals = { 1,2,3 };
auto gadget_stdvector = fillGadget< std::vector, QList, std::shared_ptr, int >(vals);
std::deque<int> val2 = { 1 ,2, 3 };
auto gadget_qvector = fillGadget< QVector, std::deque, QSharedPointer, int >(val2);
请注意,对于连续存储源容器和目标容器值的所有情况,它都不是最佳选择。