Container classes: removed templated ctors and added static methods to replace them.

This resolves an issue with infinite recursion and stack overflows in MSVC2010.
See also http://connect.microsoft.com/VisualStudio/feedback/details/522094/
This commit is contained in:
Mathew Sutcliffe
2014-01-11 01:32:24 +00:00
parent b3c650e633
commit 6a9065b37f
3 changed files with 25 additions and 33 deletions

View File

@@ -50,13 +50,6 @@ namespace BlackMisc
*/
CCollection() : m_pimpl(new Pimpl<QSet<T>>(QSet<T>())) {}
/*!
* \brief Constructor.
* \tparam C Becomes the collection's implementation type.
* \param c Initial value for the collection; typically empty, but could contain elements.
*/
template <class C> CCollection(C c) : m_pimpl(new Pimpl<C>(std::move(c))) {}
/*!
* \brief Copy constructor.
* \param other
@@ -69,13 +62,6 @@ namespace BlackMisc
*/
CCollection(CCollection &&other) : m_pimpl(other.m_pimpl.take()) {}
/*!
* \brief Assignment.
* \tparam C Becomes the collection's new implementation type.
* \param c New value for the collection; typically empty, but could contain elements.
*/
template <class C> CCollection &operator =(C c) { m_pimpl.reset(new Pimpl<C>(std::move(c))); return *this; }
/*!
* \brief Copy assignment.
* \param other
@@ -90,11 +76,19 @@ namespace BlackMisc
*/
CCollection &operator =(CCollection && other) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
/*!
* \brief Create a new collection with a specific implementation type.
* \tparam C Becomes the collection's implementation type.
* \param c Initial value for the collection; default is empty, but it could contain elements if desired. The value is copied.
* \return
*/
template <class C> static CCollection fromImpl(C c = C()) { return CCollection(new Pimpl<C>(std::move(c))); }
/*!
* \brief Change the implementation type but keep all the same elements, by copying them into the new implementation.
* \tparam C Becomes the collection's new implementation type.
*/
template <class C> void changeImpl(C = C()) { CCollection c = C(); for (auto i = cbegin(); i != cend(); ++i) c.insert(*i); *this = std::move(c); }
template <class C> void changeImpl(C = C()) { auto c = fromImpl(C()); for (auto i = cbegin(); i != cend(); ++i) c.insert(*i); *this = std::move(c); }
/*!
* \brief Like changeImpl, but uses the implementation type of another collection.
@@ -275,6 +269,8 @@ namespace BlackMisc
typedef QScopedPointer<PimplBase> PimplPtr;
PimplPtr m_pimpl;
CCollection(PimplBase *pimpl) : m_pimpl(pimpl) {} // private ctor used by fromImpl()
// using these methods to access m_pimpl.data() eases the cognitive burden of correctly forwarding const
PimplBase *pimpl() { return m_pimpl.data(); }
const PimplBase *pimpl() const { return m_pimpl.data(); }

View File

@@ -50,13 +50,6 @@ namespace BlackMisc
*/
CSequence() : m_pimpl(new Pimpl<QList<T>>(QList<T>())) {}
/*!
* \brief Constructor.
* \tparam C Becomes the sequence's implementation type.
* \param c Initial value for the sequence; typically empty, but could contain elements.
*/
template <class C> CSequence(C c) : m_pimpl(new Pimpl<C>(std::move(c))) {}
/*!
* \brief Copy constructor.
* \param other
@@ -69,13 +62,6 @@ namespace BlackMisc
*/
CSequence(CSequence &&other) : m_pimpl(other.m_pimpl.take()) {}
/*!
* \brief Assignment.
* \tparam C Becomes the sequence's new implementation type.
* \param c New value for the sequence; typically empty, but could contain elements.
*/
template <class C> CSequence &operator =(C c) { m_pimpl.reset(new Pimpl<C>(std::move(c))); return *this; }
/*!
* \brief Copy assignment.
* \param other
@@ -90,11 +76,19 @@ namespace BlackMisc
*/
CSequence &operator =(CSequence &&other) { m_pimpl.reset(other.m_pimpl.take()); return *this; }
/*!
* \brief Create a new sequence with a specific implementation type.
* \tparam C Becomes the sequence's implementation type.
* \param c Initial value for the sequence; default is empty, but it could contain elements if desired. The value is copied.
* \return
*/
template <class C> static CSequence fromImpl(C c = C()) { return CSequence(new Pimpl<C>(std::move(c))); }
/*!
* \brief Change the implementation type but keep all the same elements, by copying them into the new implementation.
* \tparam C Becomes the sequence's new implementation type.
*/
template <class C> void changeImpl(C = C()) { CSequence c = C(); for (auto i = cbegin(); i != cend(); ++i) c.push_back(*i); *this = std::move(c); }
template <class C> void changeImpl(C = C()) { auto c = fromImpl(C()); for (auto i = cbegin(); i != cend(); ++i) c.push_back(*i); *this = std::move(c); }
/*!
* \brief Like changeImpl, but uses the implementation type of another sequence.
@@ -508,6 +502,8 @@ namespace BlackMisc
typedef QScopedPointer<PimplBase> PimplPtr;
PimplPtr m_pimpl;
explicit CSequence(PimplBase *pimpl) : m_pimpl(pimpl) {} // private ctor used by fromImpl()
// using these methods to access m_pimpl.data() eases the cognitive burden of correctly forwarding const
PimplBase *pimpl() { return m_pimpl.data(); }
const PimplBase *pimpl() const { return m_pimpl.data(); }

View File

@@ -3,9 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "testcontainers.h"
#include "blackmisc/collection.h"
#include "blackmisc/sequence.h"
#include "testcontainers.h"
#include <QList>
#include <QString>
#include <vector>
@@ -19,7 +19,7 @@ namespace BlackMiscTest
{
CCollection<int> c1;
QVERIFY2(c1.empty(), "Uninitialized collection is empty");
CCollection<int> c2 = QList<int>();
auto c2 = CCollection<int>::fromImpl(QList<int>());
QVERIFY2(c1 == c2, "Uninitialized and empty collections are equal");
c1.changeImpl(std::vector<int>());
QVERIFY2(c1 == c2, "Two empty collections are equal");
@@ -42,7 +42,7 @@ namespace BlackMiscTest
{
CSequence<int> s1;
QVERIFY2(s1.empty(), "Uninitialized sequence is empty");
CSequence<int> s2 = QList<int>();
auto s2 = CSequence<int>::fromImpl(QList<int>());
QVERIFY2(s1 == s2, "Uninitialized and empty sequence are equal");
s1.changeImpl(std::vector<int>());
QVERIFY2(s1 == s2, "Two empty sequences are equal");