Commit 6b48beee authored by Eike Ziller's avatar Eike Ziller

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's avatarTobias Hunger <tobias.hunger@qt.io>
Reviewed-by: Marco Bubke's avatarMarco Bubke <marco.bubke@qt.io>
parent b054e1b1
......@@ -332,13 +332,11 @@ inserter(QSet<X> &container)
// different container types for input and output, e.g. transforming a QList into a QSet
// function:
template<template<typename> class C, // result container type
// 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
typename Value = typename SC<SCArgs...>::value_type,
typename ResultContainer = C<std::decay_t<std::result_of_t<F(Value)>>>>
typename... SCArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const SC<SCArgs...> &container, F function)
{
......@@ -348,6 +346,19 @@ decltype(auto) transform(const SC<SCArgs...> &container, F 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
typename... SCArgs, // Arguments to SC
typename Value = typename SC<SCArgs...>::value_type,
typename ResultContainer = C<std::decay_t<std::result_of_t<F(Value)>>>>
Q_REQUIRED_RESULT
decltype(auto) transform(const SC<SCArgs...> &container, F function)
{
return transform<ResultContainer>(container, function);
}
template<template<typename, typename> class C, // result container type
template<typename...> class SC, // input container type
typename F, // function 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()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment