diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h index a3659983ec4..5efaed2343b 100644 --- a/src/libs/utils/algorithm.h +++ b/src/libs/utils/algorithm.h @@ -35,6 +35,7 @@ #include #include +#include namespace Utils { @@ -140,13 +141,100 @@ auto equal(R (S::*function)() const, T value) // transform ///////////////// -// transform taking a member function pointer -template -Q_REQUIRED_RESULT -auto transform(const QList &container, R (S::*p)() const) - -> QList::type>::type> +namespace { +// needed for msvc 2010, that doesn't have a declval +// can be removed once we stop supporting it +template +T &&declval(); + +///////////////// +// helper code for transform to use back_inserter and thus push_back for everything +// and insert for QSet<> +// + +// QSetInsertIterator, straight from the standard for insert_iterator +// just without the additional parameter to insert +template + class QSetInsertIterator : + public std::iterator { - QList::type>::type> result; +protected: + Container *container; + +public: + typedef Container container_type; + explicit QSetInsertIterator (Container &x) + : container(&x) {} + QSetInsertIterator &operator=(const typename Container::value_type &value) + { container->insert(value); return *this; } + QSetInsertIterator &operator= (typename Container::value_type &&value) + { container->insert(std::move(value)); return *this; } + QSetInsertIterator&operator*() + { return *this; } + QSetInsertIterator &operator++() + { return *this; } + QSetInsertIterator operator++(int) + { return *this; } +}; + +// inserter helper function, returns a std::back_inserter for most containers +// and is overloaded for QSet<> to return a QSetInsertIterator +template +inline std::back_insert_iterator +inserter(C &container) +{ + return std::back_inserter(container); +} + +template +inline QSetInsertIterator> +inserter(QSet &container) +{ + return QSetInsertIterator>(container); +} + +// helper: removes const, volatile and references from a type +template +struct RemoveCvAndReference +{ + typedef typename std::remove_cv::type>::type type; +}; + +template +struct ResultOfFunctionWithoutCvAndReference +{ + 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> +{ + C::type> result; + result.reserve(container.size()); + std::transform(container.begin(), container.end(), + inserter(result), + function); + return result; +} + +} + +// transform taking a member function pointer +template class C, + typename T, + typename R, + typename S> +Q_REQUIRED_RESULT +auto transform(const C &container, R (S::*p)() const) + -> C::type> +{ + C::type> result; result.reserve(container.size()); std::transform(container.begin(), container.end(), std::back_inserter(result), @@ -154,25 +242,53 @@ auto transform(const QList &container, R (S::*p)() const) return result; } -namespace { -// needed for msvc 2010, that doesn't have a declval -// can be removed once we stop supporting it -template -T &&declval(); +// 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); } -// Note: add overloads for other container types as needed -template +// 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 F> // function type Q_REQUIRED_RESULT -auto transform(const QList &container, F function) - -> QList()))>::type>::type> +auto transform(const SC &container, F function) + -> C()(declval()))>::type> { - QList()))>::type>::type> result; - result.reserve(container.size()); - std::transform(container.begin(), container.end(), - std::back_inserter(result), - function); - return result; + return transform_impl(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 +template class C, // result container type + typename F> // function type +Q_REQUIRED_RESULT +auto transform(const QStringList &container, F function) + -> C()(declval()))>::type> +{ + return transform_impl(QList(container), function); } ////////////////// diff --git a/src/libs/utils/codegeneration.cpp b/src/libs/utils/codegeneration.cpp index 379eeba2009..94caf4abb68 100644 --- a/src/libs/utils/codegeneration.cpp +++ b/src/libs/utils/codegeneration.cpp @@ -110,8 +110,8 @@ void writeQtIncludeSection(const QStringList &qt4, else trans = [](const QString &i) { return i.mid(i.indexOf(QLatin1Char('/')) + 1); }; - QSet qt4Only = QSet::fromList(Utils::transform(qt4, trans)); - QSet qt5Only = QSet::fromList(Utils::transform(qt5, trans)); + QSet qt4Only = Utils::transform(qt4, trans); + QSet qt5Only = Utils::transform(qt5, trans); if (addQtVersionCheck) { QSet common = qt4Only;