forked from qt-creator/qt-creator
Support specifying complete result type in Utils::transform
Can come in handy when the function or member does not directly return the right value type for the result list, but is implicitly convertable to it. For example from pointer to class to pointer to superclass, or from int to double. const auto result = Utils::transform<QVector<double>>(v, &ValueType::intMember) Change-Id: I0e1914d70bb2580b91098dd37e85a31ca14b0ae6 Reviewed-by: Tobias Hunger <tobias.hunger@qt.io> Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -332,7 +332,21 @@ inserter(QSet<X> &container)
|
||||
|
||||
// different container types for input and output, e.g. transforming a QList into a QSet
|
||||
|
||||
// function:
|
||||
// function without result type deduction:
|
||||
template<typename ResultContainer, // complete result container type
|
||||
template<typename...> class SC, // input container type
|
||||
typename F, // function type
|
||||
typename... SCArgs> // Arguments to SC
|
||||
Q_REQUIRED_RESULT
|
||||
decltype(auto) transform(const SC<SCArgs...> &container, F function)
|
||||
{
|
||||
ResultContainer result;
|
||||
result.reserve(container.size());
|
||||
std::transform(std::begin(container), std::end(container), inserter(result), function);
|
||||
return result;
|
||||
}
|
||||
|
||||
// function with result type deduction:
|
||||
template<template<typename> class C, // result container type
|
||||
template<typename...> class SC, // input container type
|
||||
typename F, // function type
|
||||
@@ -342,10 +356,7 @@ template<template<typename> class C, // result container type
|
||||
Q_REQUIRED_RESULT
|
||||
decltype(auto) transform(const SC<SCArgs...> &container, F function)
|
||||
{
|
||||
ResultContainer result;
|
||||
result.reserve(container.size());
|
||||
std::transform(std::begin(container), std::end(container), inserter(result), function);
|
||||
return result;
|
||||
return transform<ResultContainer>(container, function);
|
||||
}
|
||||
|
||||
template<template<typename, typename> class C, // result container type
|
||||
@@ -358,13 +369,10 @@ template<template<typename, typename> class C, // result container type
|
||||
Q_REQUIRED_RESULT
|
||||
decltype(auto) transform(const SC<SCArgs...> &container, F function)
|
||||
{
|
||||
ResultContainer result;
|
||||
result.reserve(container.size());
|
||||
std::transform(std::begin(container), std::end(container), inserter(result), function);
|
||||
return result;
|
||||
return transform<ResultContainer>(container, function);
|
||||
}
|
||||
|
||||
// member function:
|
||||
// member function without result type deduction:
|
||||
template<template<typename...> class C, // result container type
|
||||
template<typename...> class SC, // input container type
|
||||
typename R,
|
||||
@@ -376,7 +384,31 @@ decltype(auto) transform(const SC<SCArgs...> &container, R (S::*p)() const)
|
||||
return transform<C, SC>(container, std::mem_fn(p));
|
||||
}
|
||||
|
||||
// members:
|
||||
// member function with result type deduction:
|
||||
template<typename ResultContainer, // complete result container type
|
||||
template<typename...> class SC, // input container type
|
||||
typename R,
|
||||
typename S,
|
||||
typename... SCArgs> // Arguments to SC
|
||||
Q_REQUIRED_RESULT
|
||||
decltype(auto) transform(const SC<SCArgs...> &container, R (S::*p)() const)
|
||||
{
|
||||
return transform<ResultContainer, SC>(container, std::mem_fn(p));
|
||||
}
|
||||
|
||||
// member without result type deduction:
|
||||
template<typename ResultContainer, // complete result container type
|
||||
template<typename...> class SC, // input container
|
||||
typename R,
|
||||
typename S,
|
||||
typename... SCArgs> // Arguments to SC
|
||||
Q_REQUIRED_RESULT
|
||||
decltype(auto) transform(const SC<SCArgs...> &container, R S::*p)
|
||||
{
|
||||
return transform<ResultContainer, SC>(container, std::mem_fn(p));
|
||||
}
|
||||
|
||||
// member with result type deduction:
|
||||
template<template<typename...> class C, // result container
|
||||
template<typename...> class SC, // input container
|
||||
typename R,
|
||||
|
@@ -55,16 +55,23 @@ int stringToInt(const QString &s)
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct Struct
|
||||
|
||||
struct BaseStruct
|
||||
{
|
||||
Struct(int m) : member(m) {}
|
||||
bool operator==(const Struct &other) const { return member == other.member; }
|
||||
BaseStruct(int m) : member(m) {}
|
||||
bool operator==(const BaseStruct &other) const { return member == other.member; }
|
||||
|
||||
int member;
|
||||
};
|
||||
|
||||
struct Struct : public BaseStruct
|
||||
{
|
||||
Struct(int m) : BaseStruct(m) {}
|
||||
bool isOdd() const { return member % 2 == 1; }
|
||||
bool isEven() const { return !isOdd(); }
|
||||
|
||||
int getMember() const { return member; }
|
||||
|
||||
int member;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -248,6 +255,57 @@ void tst_Algorithm::transform()
|
||||
Utils::sort(trans);
|
||||
QCOMPARE(trans, QList<double>({1.5, 7.5, 17.5}));
|
||||
}
|
||||
{
|
||||
// specific result container with one template parameter (QVector)
|
||||
std::vector<int> v({1, 2, 3, 4});
|
||||
const QVector<BaseStruct *> trans = Utils::transform<QVector<BaseStruct *>>(v, [](int i) {
|
||||
return new Struct(i);
|
||||
});
|
||||
QCOMPARE(trans.size(), 4);
|
||||
QCOMPARE(trans.at(0)->member, 1);
|
||||
QCOMPARE(trans.at(1)->member, 2);
|
||||
QCOMPARE(trans.at(2)->member, 3);
|
||||
QCOMPARE(trans.at(3)->member, 4);
|
||||
qDeleteAll(trans);
|
||||
}
|
||||
{
|
||||
// specific result container with one of two template parameters (std::vector)
|
||||
std::vector<int> v({1, 2, 3, 4});
|
||||
const std::vector<BaseStruct *> trans
|
||||
= Utils::transform<std::vector<BaseStruct *>>(v, [](int i) { return new Struct(i); });
|
||||
QCOMPARE(trans.size(), 4ul);
|
||||
QCOMPARE(trans.at(0)->member, 1);
|
||||
QCOMPARE(trans.at(1)->member, 2);
|
||||
QCOMPARE(trans.at(2)->member, 3);
|
||||
QCOMPARE(trans.at(3)->member, 4);
|
||||
qDeleteAll(trans);
|
||||
}
|
||||
{
|
||||
// specific result container with two template parameters (std::vector)
|
||||
std::vector<int> v({1, 2, 3, 4});
|
||||
const std::vector<BaseStruct *, std::allocator<BaseStruct *>> trans
|
||||
= Utils::transform<std::vector<BaseStruct *, std::allocator<BaseStruct *>>>(v, [](int i) {
|
||||
return new Struct(i);
|
||||
});
|
||||
QCOMPARE(trans.size(), 4ul);
|
||||
QCOMPARE(trans.at(0)->member, 1);
|
||||
QCOMPARE(trans.at(1)->member, 2);
|
||||
QCOMPARE(trans.at(2)->member, 3);
|
||||
QCOMPARE(trans.at(3)->member, 4);
|
||||
qDeleteAll(trans);
|
||||
}
|
||||
{
|
||||
// specific result container with member function
|
||||
QList<Struct> v({1, 2, 3, 4});
|
||||
const QVector<double> trans = Utils::transform<QVector<double>>(v, &Struct::getMember);
|
||||
QCOMPARE(trans, QVector<double>({1.0, 2.0, 3.0, 4.0}));
|
||||
}
|
||||
{
|
||||
// specific result container with member
|
||||
QList<Struct> v({1, 2, 3, 4});
|
||||
const QVector<double> trans = Utils::transform<QVector<double>>(v, &Struct::member);
|
||||
QCOMPARE(trans, QVector<double>({1.0, 2.0, 3.0, 4.0}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Algorithm::sort()
|
||||
|
Reference in New Issue
Block a user