forked from qt-creator/qt-creator
Utils::transform: Add missing overloads, simplify implementation
Use a helper class so that the actual implementation is shared and introduce a helper class for treating QStringList and other qt containers in the same way. There are now 2² overloads, because: - member function pointer vs everything else - same container type, different container types Change-Id: I343ca7d4e0007f7146b2e646c436c22174e27779 Reviewed-by: Daniel Teske <daniel.teske@theqtcompany.com>
This commit is contained in:
@@ -200,95 +200,137 @@ struct RemoveCvAndReference
|
|||||||
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
|
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F, typename T>
|
// abstraction to treat Container<T> and QStringList similarly
|
||||||
struct ResultOfFunctionWithoutCvAndReference
|
template<typename T>
|
||||||
|
struct ContainerType
|
||||||
{
|
{
|
||||||
typedef typename RemoveCvAndReference<decltype(declval<F>()(declval<T>()))>::type type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// actual implementation of transform
|
// specialization for qt container T_Container<T_Type>
|
||||||
template<template<typename> class C, // result container type
|
template<template<typename> class T_Container, typename T_Type>
|
||||||
template<typename> class SC, // input container type
|
struct ContainerType<T_Container<T_Type>> {
|
||||||
typename T, // element type of input container
|
typedef T_Type ElementType;
|
||||||
typename F> // function type
|
|
||||||
Q_REQUIRED_RESULT
|
template<class NewElementType>
|
||||||
auto transform_impl(const SC<T> &container, F function)
|
struct WithElementType
|
||||||
-> C<typename ResultOfFunctionWithoutCvAndReference<F, T>::type>
|
{
|
||||||
|
typedef T_Container<NewElementType> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// specialization for QStringList
|
||||||
|
template<>
|
||||||
|
struct ContainerType<QStringList>
|
||||||
{
|
{
|
||||||
C<typename ResultOfFunctionWithoutCvAndReference<F, T>::type> result;
|
typedef QString ElementType;
|
||||||
|
|
||||||
|
template<class NewElementType>
|
||||||
|
struct WithElementType
|
||||||
|
{
|
||||||
|
typedef QList<NewElementType> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual implementation of transform
|
||||||
|
template<typename C, // result container type
|
||||||
|
typename SC> // input container type
|
||||||
|
struct TransformImpl {
|
||||||
|
template <typename F>
|
||||||
|
Q_REQUIRED_RESULT
|
||||||
|
static C call(const SC &container, F function)
|
||||||
|
{
|
||||||
|
C result;
|
||||||
result.reserve(container.size());
|
result.reserve(container.size());
|
||||||
std::transform(container.begin(), container.end(),
|
std::transform(container.begin(), container.end(),
|
||||||
inserter(result),
|
inserter(result),
|
||||||
function);
|
function);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R, typename S>
|
||||||
|
Q_REQUIRED_RESULT
|
||||||
|
static C call(const SC &container, R (S::*p)() const)
|
||||||
|
{
|
||||||
|
return call(container, std::mem_fn(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// same container type for input and output, e.g. transforming a QList<QString> into QList<int>
|
||||||
|
// or QStringList -> QList<>
|
||||||
|
template<typename C, // container
|
||||||
|
typename F>
|
||||||
|
Q_REQUIRED_RESULT
|
||||||
|
auto transform(const C &container, F function)
|
||||||
|
-> typename ContainerType<C>::template WithElementType< // the type C<stripped return type of F>
|
||||||
|
typename RemoveCvAndReference< // the return type of F stripped
|
||||||
|
decltype(declval<F>()(declval<typename ContainerType<C>::ElementType>())) // the return type of F
|
||||||
|
>::type
|
||||||
|
>::type
|
||||||
|
{
|
||||||
|
return TransformImpl<
|
||||||
|
typename ContainerType<C>::template WithElementType< // the type C<stripped return type>
|
||||||
|
typename RemoveCvAndReference< // the return type stripped
|
||||||
|
decltype(declval<F>()(declval<typename ContainerType<C>::ElementType>())) // the return type of F
|
||||||
|
>::type
|
||||||
|
>::type,
|
||||||
|
C
|
||||||
|
>::call(container, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// same container type for member function pointer
|
||||||
|
template<typename C,
|
||||||
// transform taking a member function pointer
|
|
||||||
template<template<typename> class C,
|
|
||||||
typename T,
|
|
||||||
typename R,
|
typename R,
|
||||||
typename S>
|
typename S>
|
||||||
Q_REQUIRED_RESULT
|
Q_REQUIRED_RESULT
|
||||||
auto transform(const C<T> &container, R (S::*p)() const)
|
auto transform(const C &container, R (S::*p)() const)
|
||||||
-> C<typename RemoveCvAndReference<R>::type>
|
->typename ContainerType<C>::template WithElementType<typename RemoveCvAndReference<R>::type>::type
|
||||||
{
|
{
|
||||||
C<typename RemoveCvAndReference<R>::type> result;
|
return TransformImpl<
|
||||||
result.reserve(container.size());
|
typename ContainerType<C>::template WithElementType< // the type C<stripped R>
|
||||||
std::transform(container.begin(), container.end(),
|
typename RemoveCvAndReference<R>::type // stripped R
|
||||||
std::back_inserter(result),
|
>::type,
|
||||||
std::mem_fn(p));
|
C
|
||||||
return result;
|
>::call(container, p);
|
||||||
}
|
|
||||||
|
|
||||||
// same container type for input and output, e.g. transforming a QList<QString> into QList<int>
|
|
||||||
template<template<typename> class C, // container
|
|
||||||
typename T, // element type
|
|
||||||
typename F> // function type
|
|
||||||
Q_REQUIRED_RESULT
|
|
||||||
auto transform(const C<T> &container, F function)
|
|
||||||
-> C<typename RemoveCvAndReference<decltype(declval<F>()(declval<T>()))>::type>
|
|
||||||
{
|
|
||||||
return transform_impl<QList>(container, function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// different container types for input and output, e.g. transforming a QList into a QSet
|
// different container types for input and output, e.g. transforming a QList into a QSet
|
||||||
template<template<typename> class C, // result container type
|
template<template<typename> class C, // result container type
|
||||||
template<typename> class SC, // input container type
|
typename SC, // input container type
|
||||||
typename T, // element type of input container
|
|
||||||
typename F> // function type
|
typename F> // function type
|
||||||
Q_REQUIRED_RESULT
|
Q_REQUIRED_RESULT
|
||||||
auto transform(const SC<T> &container, F function)
|
auto transform(const SC &container, F function)
|
||||||
-> C<typename RemoveCvAndReference<decltype(declval<F>()(declval<T>()))>::type>
|
-> C< // container C<stripped return type of F>
|
||||||
|
typename RemoveCvAndReference< // stripped return type of F
|
||||||
|
decltype(declval<F>()(declval<typename ContainerType<SC>::ElementType>())) // return type of F
|
||||||
|
>::type>
|
||||||
{
|
{
|
||||||
return transform_impl(container, function);
|
return TransformImpl<
|
||||||
|
C< // result container type
|
||||||
|
typename RemoveCvAndReference< // stripped
|
||||||
|
decltype(declval<F>()(declval<typename ContainerType<SC>::ElementType>())) // return type of F
|
||||||
|
>::type>,
|
||||||
|
SC
|
||||||
|
>::call(container, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// different container types for input and output, e.g. transforming a QList into a QSet
|
||||||
//////////
|
// for member function pointers
|
||||||
// transform for QStringList, because that isn't a specialization but a separate type
|
|
||||||
// and g++ doesn't want to use the above templates for that
|
|
||||||
// clang and msvc do find the base class QList<QString>
|
|
||||||
//////////
|
|
||||||
|
|
||||||
// QStringList -> QList<>
|
|
||||||
template<typename F> // function type
|
|
||||||
Q_REQUIRED_RESULT
|
|
||||||
auto transform(const QStringList &container, F function)
|
|
||||||
-> QList<typename RemoveCvAndReference<decltype(declval<F>()(declval<QString>()))>::type>
|
|
||||||
{
|
|
||||||
return transform_impl<QList>(QList<QString>(container), function);
|
|
||||||
}
|
|
||||||
|
|
||||||
// QStringList -> any container type
|
|
||||||
template<template<typename> class C, // result container type
|
template<template<typename> class C, // result container type
|
||||||
typename F> // function type
|
typename SC, // input container type
|
||||||
|
typename R,
|
||||||
|
typename S>
|
||||||
Q_REQUIRED_RESULT
|
Q_REQUIRED_RESULT
|
||||||
auto transform(const QStringList &container, F function)
|
auto transform(const SC &container, R (S::*p)())
|
||||||
-> C<typename RemoveCvAndReference<decltype(declval<F>()(declval<QString>()))>::type>
|
-> C<typename RemoveCvAndReference<R>::type>
|
||||||
{
|
{
|
||||||
return transform_impl<C>(QList<QString>(container), function);
|
return TransformImpl<
|
||||||
|
C<typename RemoveCvAndReference<R>::type>,
|
||||||
|
SC
|
||||||
|
>::call(container, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user