From 0b5866bcf869596fda2c094e352ff9eb1284618c Mon Sep 17 00:00:00 2001 From: Nikita Baryshnikov Date: Wed, 5 Nov 2014 11:45:40 +0300 Subject: [PATCH] Utils::transform: Add missing overloads, simplify implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/libs/utils/algorithm.h | 174 +++++++++++++++++++++++-------------- 1 file changed, 108 insertions(+), 66 deletions(-) diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h index 5efaed2343b..f918d996681 100644 --- a/src/libs/utils/algorithm.h +++ b/src/libs/utils/algorithm.h @@ -200,95 +200,137 @@ struct RemoveCvAndReference typedef typename std::remove_cv::type>::type type; }; -template -struct ResultOfFunctionWithoutCvAndReference +// abstraction to treat Container and QStringList similarly +template +struct ContainerType { - typedef typename RemoveCvAndReference()(declval()))>::type type; + }; -// actual implementation of transform -template class C, // result container type - template class SC, // input container type - typename T, // element type of input container - typename F> // function type -Q_REQUIRED_RESULT -auto transform_impl(const SC &container, F function) - -> C::type> +// specialization for qt container T_Container +template class T_Container, typename T_Type> +struct ContainerType> { + typedef T_Type ElementType; + + template + struct WithElementType + { + typedef T_Container type; + }; +}; + +// specialization for QStringList +template<> +struct ContainerType { - C::type> result; - result.reserve(container.size()); - std::transform(container.begin(), container.end(), - inserter(result), - function); - return result; -} + typedef QString ElementType; + + template + struct WithElementType + { + typedef QList type; + }; +}; } -// transform taking a member function pointer -template class C, - typename T, +// actual implementation of transform +template // input container type +struct TransformImpl { + template + Q_REQUIRED_RESULT + static C call(const SC &container, F function) + { + C result; + result.reserve(container.size()); + std::transform(container.begin(), container.end(), + inserter(result), + function); + return result; + } + + template + 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 into QList +// or QStringList -> QList<> +template +Q_REQUIRED_RESULT +auto transform(const C &container, F function) +-> typename ContainerType::template WithElementType< // the type C + typename RemoveCvAndReference< // the return type of F stripped + decltype(declval()(declval::ElementType>())) // the return type of F + >::type + >::type +{ + return TransformImpl< + typename ContainerType::template WithElementType< // the type C + typename RemoveCvAndReference< // the return type stripped + decltype(declval()(declval::ElementType>())) // the return type of F + >::type + >::type, + C + >::call(container, function); +} + +// same container type for member function pointer +template Q_REQUIRED_RESULT -auto transform(const C &container, R (S::*p)() const) - -> C::type> +auto transform(const C &container, R (S::*p)() const) + ->typename ContainerType::template WithElementType::type>::type { - C::type> result; - result.reserve(container.size()); - std::transform(container.begin(), container.end(), - std::back_inserter(result), - std::mem_fn(p)); - return result; -} - -// same container type for input and output, e.g. transforming a QList into QList -template class C, // container - typename T, // element type - typename F> // function type -Q_REQUIRED_RESULT -auto transform(const C &container, F function) - -> C()(declval()))>::type> -{ - return transform_impl(container, function); + return TransformImpl< + typename ContainerType::template WithElementType< // the type C + typename RemoveCvAndReference::type // stripped R + >::type, + C + >::call(container, p); } // different container types for input and output, e.g. transforming a QList into a QSet template class C, // result container type - template class SC, // input container type - typename T, // element type of input container + typename SC, // input container type typename F> // function type Q_REQUIRED_RESULT -auto transform(const SC &container, F function) - -> C()(declval()))>::type> +auto transform(const SC &container, F function) + -> C< // container C + typename RemoveCvAndReference< // stripped return type of F + decltype(declval()(declval::ElementType>())) // return type of F + >::type> { - return transform_impl(container, function); + return TransformImpl< + C< // result container type + typename RemoveCvAndReference< // stripped + decltype(declval()(declval::ElementType>())) // return type of F + >::type>, + SC + >::call(container, function); } - -////////// -// 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 -////////// - -// QStringList -> QList<> -template // function type -Q_REQUIRED_RESULT -auto transform(const QStringList &container, F function) - -> QList()(declval()))>::type> -{ - return transform_impl(QList(container), function); -} - -// QStringList -> any container type +// different container types for input and output, e.g. transforming a QList into a QSet +// for member function pointers template class C, // result container type - typename F> // function type + typename SC, // input container type + typename R, + typename S> Q_REQUIRED_RESULT -auto transform(const QStringList &container, F function) - -> C()(declval()))>::type> +auto transform(const SC &container, R (S::*p)()) + -> C::type> { - return transform_impl(QList(container), function); + return TransformImpl< + C::type>, + SC + >::call(container, p); } //////////////////