tst_compiler: check more cases for RVALUE_REFS

Check that we can use std::forward, and that the compiler
synthesizes move special member functions when it should.

MSVC only supports the latter since the Nov 2013 CTP,
which, for our intents and purposes, means VC2015.

Change-Id: I8d8e4ae064abce90076a05b3b637950ab7d21dac
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Marc Mutz 2015-11-10 12:41:37 +01:00
parent ecb6835a9f
commit 5660ce6004

View File

@ -1128,24 +1128,88 @@ void tst_Compiler::cxx11_ref_qualifiers()
#endif
}
class MoveDefinedQString {
QString s;
public:
MoveDefinedQString() : s() {}
explicit MoveDefinedQString(const QString &s) : s(s) {}
MoveDefinedQString(const MoveDefinedQString &other) : s(other.s) {}
#ifdef Q_COMPILER_RVALUE_REFS
MoveDefinedQString(MoveDefinedQString &&other) : s(std::move(other.s)) { other.s.clear(); }
MoveDefinedQString &operator=(MoveDefinedQString &&other)
{ s = std::move(other.s); other.s.clear(); return *this; }
#endif
MoveDefinedQString &operator=(const MoveDefinedQString &other) { s = other.s; return *this; }
private:
friend bool operator==(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs)
{ return lhs.s == rhs.s; }
friend bool operator!=(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs)
{ return !operator==(lhs, rhs); }
friend char* toString(const MoveDefinedQString &mds)
{ using namespace QTest; return toString(mds.s); }
};
void tst_Compiler::cxx11_rvalue_refs()
{
#ifndef Q_COMPILER_RVALUE_REFS
QSKIP("Compiler does not support C++11 feature");
#else
int i = 1;
i = std::move(i);
// we require std::move:
{
int i = 1;
i = std::move(i);
QString s = "Hello";
QString t = std::move(s);
QCOMPARE(t, QString("Hello"));
MoveDefinedQString s("Hello");
MoveDefinedQString t = std::move(s);
QCOMPARE(t, MoveDefinedQString("Hello"));
QCOMPARE(s, MoveDefinedQString());
s = t;
t = std::move(s);
QCOMPARE(t, QString("Hello"));
s = t;
t = std::move(s);
QCOMPARE(t, MoveDefinedQString("Hello"));
QCOMPARE(s, MoveDefinedQString());
QString &&r = std::move(s);
QCOMPARE(r, QString("Hello"));
MoveDefinedQString &&r = std::move(t); // no actual move!
QCOMPARE(r, MoveDefinedQString("Hello"));
QCOMPARE(t, MoveDefinedQString("Hello")); // so 't' is unchanged
}
// we require std::forward:
{
MoveDefinedQString s("Hello");
MoveDefinedQString s2 = std::forward<MoveDefinedQString>(s); // forward as rvalue
QCOMPARE(s2, MoveDefinedQString("Hello"));
QCOMPARE(s, MoveDefinedQString());
MoveDefinedQString s3 = std::forward<MoveDefinedQString&>(s2); // forward as lvalue
QCOMPARE(s2, MoveDefinedQString("Hello"));
QCOMPARE(s3, MoveDefinedQString("Hello"));
}
// supported by MSVC only from November 2013 CTP, but only check for VC2015:
# if !defined(Q_CC_MSVC) || defined(Q_CC_INTEL) || _MSC_VER >= 1900 // VS14 == VC2015
// we require automatic generation of move special member functions:
{
struct M { MoveDefinedQString s1, s2; };
M m1 = { MoveDefinedQString("Hello"), MoveDefinedQString("World") };
QCOMPARE(m1.s1, MoveDefinedQString("Hello"));
QCOMPARE(m1.s2, MoveDefinedQString("World"));
M m2 = std::move(m1);
QCOMPARE(m1.s1, MoveDefinedQString());
QCOMPARE(m1.s2, MoveDefinedQString());
QCOMPARE(m2.s1, MoveDefinedQString("Hello"));
QCOMPARE(m2.s2, MoveDefinedQString("World"));
M m3;
QCOMPARE(m3.s1, MoveDefinedQString());
QCOMPARE(m3.s2, MoveDefinedQString());
m3 = std::move(m2);
QCOMPARE(m2.s1, MoveDefinedQString());
QCOMPARE(m2.s2, MoveDefinedQString());
QCOMPARE(m3.s1, MoveDefinedQString("Hello"));
QCOMPARE(m3.s2, MoveDefinedQString("World"));
}
# endif // MSVC < 2015
#endif
}