refs #715 Support implicit conversion from CRange to QSet.

This commit is contained in:
Mathew Sutcliffe
2016-07-28 20:45:51 +01:00
parent 08b404906d
commit b449487a71
3 changed files with 94 additions and 1 deletions

View File

@@ -15,6 +15,7 @@
#define BLACKMISC_ITERATOR_H
#include "optional.h"
#include "typetraits.h"
#include <QScopedPointer>
#include <algorithm>
#include <type_traits>
@@ -26,6 +27,72 @@ namespace BlackMisc
{
namespace Iterators
{
/*!
* Configurable output iterator using a provided functor to do the insertion.
*/
template <class F> class OutputIterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
//! Constructor
//! @{
explicit OutputIterator(const F &func) : m_func(func) {}
explicit OutputIterator(F &&func) : m_func(std::move(func)) {}
//! @}
//! Advance the iterator (no-op)
//! @{
OutputIterator &operator ++() { return *this; }
OutputIterator operator ++(int) { return *this; }
//! @}
//! Dereference (no-op)
OutputIterator &operator *() { return *this; }
//! Assignment operator performs the output
template <typename T, std::enable_if_t<! std::is_convertible<T, OutputIterator>::value, int> = 0>
OutputIterator &operator =(T &&value) { m_func(std::forward<T>(value)); return *this; }
//! Copy assignment operator
OutputIterator &operator =(const OutputIterator &other)
{
// Work around lambda's deleted copy assignment operator
this->~OutputIterator();
return *new (this) OutputIterator(other);
}
private:
F m_func;
};
/*!
* Return an output iterator of type deduced from the argument.
*/
template <class F> auto makeOutputIterator(F &&func)
{
return OutputIterator<std::decay_t<F>>(std::forward<F>(func));
}
namespace Private
{
//! \private
template <class T> auto makeInsertIterator(T &container, std::true_type)
{
return makeOutputIterator([&container](auto &&v) { container.push_back(std::forward<decltype(v)>(v)); });
}
//! \private
template <class T> auto makeInsertIterator(T &container, std::false_type)
{
return makeOutputIterator([&container](auto &&v) { container.insert(std::forward<decltype(v)>(v)); });
}
}
/*!
* Return an insert iterator appropriate to the container type (uses push_back or insert).
*/
template <class T> auto makeInsertIterator(T &container)
{
return Private::makeInsertIterator(container, HasPushBack<T>());
}
/*!
* Iterator wrapper for Qt's STL-style associative container iterators, when dereferenced return the key instead of the value.

View File

@@ -206,7 +206,7 @@ namespace BlackMisc
T to() const
{
T container;
std::copy(begin(), end(), std::back_inserter(container));
std::copy(begin(), end(), Iterators::makeInsertIterator(container));
return container;
}

View File

@@ -49,6 +49,32 @@ namespace BlackMisc
//! \endcond
#ifdef Q_CC_MSVC // work around what seems to be an expression SFINAE bug in MSVC
namespace Private
{
struct HasPushBackHelper
{
struct Base { int push_back; };
template <typename T> struct Derived : public T, public Base {};
template <typename T, T> struct TypeCheck {};
template <typename T> static std::false_type test(TypeCheck<decltype(&Base::push_back), &Derived<T>::push_back> *);
template <typename T> static std::true_type test(...);
};
}
template <typename T>
using HasPushBack = decltype(Private::HasPushBackHelper::test<T>(nullptr));
#else
/*!
* Trait which is true if the expression a.push_back(v) is valid when a and v are instances of T and T::value_type.
*/
template <typename T, typename = void_t<>>
struct HasPushBack : public std::false_type {};
//! \cond
template <typename T>
struct HasPushBack<T, void_t<decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))>> : public std::true_type {};
//! \endcond
#endif
#ifdef Q_CC_MSVC
namespace Private
{
struct HasGetLogCategoriesHelper