Fix support for std::function as continuation handler

This commit is contained in:
Simon Brunel 2020-02-06 22:31:36 +01:00
parent 58738a5604
commit 78417b5813
8 changed files with 493 additions and 58 deletions

View File

@ -27,7 +27,7 @@ public:
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type = 0>
inline QPromiseBase(F resolver);
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type = 0>
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type = 0>
inline QPromiseBase(F resolver);
QPromiseBase(const QPromiseBase<T>& other): m_d(other.m_d) {}

View File

@ -30,7 +30,7 @@ inline QPromiseBase<T>::QPromiseBase(F callback)
}
template <typename T>
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count != 1, int>::type>
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type>
inline QPromiseBase<T>::QPromiseBase(F callback)
: m_d(new QtPromisePrivate::PromiseData<T>())
{

View File

@ -28,12 +28,8 @@ using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::t
template <typename T>
struct HasCallOperator
{
template <typename U>
static char check(decltype(&U::operator(), char(0)));
template <typename U>
static char (&check(...))[2];
template <typename U> static char check(decltype(&U::operator(), char(0)));
template <typename U> static char (&check(...))[2];
static const bool value = (sizeof(check<T>(0)) == 1);
};
@ -58,73 +54,57 @@ struct ArgsTraits<>
static const size_t count = 0;
};
template <typename T, typename Enable = void>
struct ArgsOf : public ArgsTraits<>
// Fallback implementation (type not supported).
template <typename T, typename Enabled = void>
struct ArgsOf
{ };
// Partial specialization for null function.
template <>
struct ArgsOf<std::nullptr_t> : public ArgsTraits<>
{ };
// Partial specialization for type with a non-overloaded operator().
// This applies to lambda, std::function but not to std::bind result.
template <typename T>
struct ArgsOf<T, typename std::enable_if<HasCallOperator<T>::value>::type>
: public ArgsOf<decltype(&T::operator())>
{ };
template <typename TReturn, typename... Args>
struct ArgsOf<TReturn(Args...)> : public ArgsTraits<Args...>
{ };
template <typename TReturn, typename... Args>
struct ArgsOf<TReturn(*)(Args...)> : public ArgsTraits<Args...>
{ };
template <typename T, typename TReturn, typename... Args>
struct ArgsOf<TReturn(T::*)(Args...)> : public ArgsTraits<Args...>
{ };
template <typename T, typename TReturn, typename... Args>
struct ArgsOf<TReturn(T::*)(Args...) const> : public ArgsTraits<Args...>
{ };
template <typename T, typename TReturn, typename... Args>
struct ArgsOf<TReturn(T::*)(Args...) volatile> : public ArgsTraits<Args...>
{ };
template <typename T, typename TReturn, typename... Args>
struct ArgsOf<TReturn(T::*)(Args...) const volatile> : public ArgsTraits<Args...>
{ };
template <typename T>
struct ArgsOf<std::function<T>> : public ArgsOf<T>
{ };
// Partial specialization to remove reference and rvalue (e.g. lambda, std::function, etc.).
template <typename T>
struct ArgsOf<T&> : public ArgsOf<T>
{ };
template <typename T>
struct ArgsOf<const T&> : public ArgsOf<T>
{ };
template <typename T>
struct ArgsOf<volatile T&> : public ArgsOf<T>
{ };
template <typename T>
struct ArgsOf<const volatile T&> : public ArgsOf<T>
{ };
template <typename T>
struct ArgsOf<T&&> : public ArgsOf<T>
{ };
template <typename T>
struct ArgsOf<const T&&> : public ArgsOf<T>
// Partial specialization for function type.
template <typename R, typename... Args>
struct ArgsOf<R(Args...)> : public ArgsTraits<Args...>
{ };
template <typename T>
struct ArgsOf<volatile T&&> : public ArgsOf<T>
// Partial specialization for function pointer.
template <typename R, typename... Args>
struct ArgsOf<R(*)(Args...)> : public ArgsTraits<Args...>
{ };
template <typename T>
struct ArgsOf<const volatile T&&> : public ArgsOf<T>
// Partial specialization for pointer-to-member-function (i.e. operator()'s).
template <typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...)> : public ArgsTraits<Args...>
{ };
template <typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...) const> : public ArgsTraits<Args...>
{ };
template <typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...) volatile> : public ArgsTraits<Args...>
{ };
template <typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...) const volatile> : public ArgsTraits<Args...>
{ };
} // namespace QtPromisePrivate

View File

@ -5,6 +5,7 @@ add_subdirectory(deprecations)
add_subdirectory(exceptions)
add_subdirectory(future)
add_subdirectory(helpers)
add_subdirectory(internals)
add_subdirectory(qpromise)
add_subdirectory(qpromiseconnections)
add_subdirectory(requirements)

View File

@ -0,0 +1,4 @@
qtpromise_add_test(internals_argsof
SOURCES
tst_argsof.cpp
)

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) Simon Brunel, https://github.com/simonbrunel
*
* This source code is licensed under the MIT license found in
* the LICENSE file in the root directory of this source tree.
*/
// QtPromise
#include <QtPromise>
// Qt
#include <QtTest>
using namespace QtPromisePrivate;
class tst_internals_argsof : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void nullFunction();
void basicFunction();
void callOperator();
void stdFunction();
void lambda();
}; // class tst_argsof
QTEST_MAIN(tst_internals_argsof)
#include "tst_argsof.moc"
#define TEST_ARGS_FOR_TYPE(T, E) \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<T>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<T&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<T&&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const T>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const T&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const T&&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<volatile T>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<volatile T&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<volatile T&&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const volatile T>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const volatile T&>::first, E>::value)); \
Q_STATIC_ASSERT((std::is_same<typename ArgsOf<const volatile T&&>::first, E>::value));
namespace {
const float kRes = 0.42f;
float fnNoArg() { return kRes; }
float fnOneArg(float v) { return v; }
float fnManyArgs(const float& v0, int, char*) { return v0; }
struct OpNoArg { float operator()() { return kRes; } };
struct OpOneArg { float operator()(float v) { return v; } };
struct OpManyArgs { float operator()(const float& v, int, char*) { return v; } };
struct OpCNoArg { float operator()() const { return kRes; } };
struct OpCOneArg { float operator()(float v) const { return v; } };
struct OpCManyArgs { float operator()(const float& v, int, char*) const { return v; } };
struct OpVNoArg { float operator()() volatile { return kRes; } };
struct OpVOneArg { float operator()(float v) volatile { return v; } };
struct OpVManyArgs { float operator()(const float& v, int, char*) volatile { return v; } };
struct OpCVNoArg { float operator()() const volatile { return kRes; } };
struct OpCVOneArg { float operator()(float v) const volatile { return v; } };
struct OpCVManyArgs { float operator()(const float& v, int, char*) const volatile { return v; } };
} // namespace
void tst_internals_argsof::initTestCase()
{
Q_UNUSED(fnNoArg())
Q_UNUSED(fnOneArg(42))
Q_UNUSED(fnManyArgs(42, 42, nullptr))
}
void tst_internals_argsof::nullFunction()
{
Q_STATIC_ASSERT((std::is_same<ArgsOf<std::nullptr_t>::first, void>::value));
}
void tst_internals_argsof::basicFunction()
{
// Function type.
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(fnNoArg)>::first, void>::value));
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(fnOneArg)>::first, float>::value));
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(fnManyArgs)>::first, const float&>::value));
// Function pointer type.
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(&fnNoArg)>::first, void>::value));
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(&fnOneArg)>::first, float>::value));
Q_STATIC_ASSERT((std::is_same<ArgsOf<decltype(&fnManyArgs)>::first, const float&>::value));
}
void tst_internals_argsof::callOperator()
{
// non-const
TEST_ARGS_FOR_TYPE(OpNoArg, void);
TEST_ARGS_FOR_TYPE(OpOneArg, float);
TEST_ARGS_FOR_TYPE(OpManyArgs, const float&);
// const
TEST_ARGS_FOR_TYPE(OpCNoArg, void);
TEST_ARGS_FOR_TYPE(OpCOneArg, float);
TEST_ARGS_FOR_TYPE(OpCManyArgs, const float&);
// volatile
TEST_ARGS_FOR_TYPE(OpVNoArg, void);
TEST_ARGS_FOR_TYPE(OpVOneArg, float);
TEST_ARGS_FOR_TYPE(OpVManyArgs, const float&);
// const volatile
TEST_ARGS_FOR_TYPE(OpCVNoArg, void);
TEST_ARGS_FOR_TYPE(OpCVOneArg, float);
TEST_ARGS_FOR_TYPE(OpCVManyArgs, const float&);
}
void tst_internals_argsof::stdFunction()
{
TEST_ARGS_FOR_TYPE(std::function<void()>, void);
TEST_ARGS_FOR_TYPE(std::function<void(float)>, float);
TEST_ARGS_FOR_TYPE(std::function<void(const float&, int, char**)>, const float&);
}
void tst_internals_argsof::lambda()
{
auto lNoArg = []() {};
auto lOneArg = [](float) {};
auto lManyArgs = [](const float&, int, char**) {};
auto lMutable = [](const float&, int, char**) mutable {};
TEST_ARGS_FOR_TYPE(decltype(lNoArg), void);
TEST_ARGS_FOR_TYPE(decltype(lOneArg), float);
TEST_ARGS_FOR_TYPE(decltype(lManyArgs), const float&);
TEST_ARGS_FOR_TYPE(decltype(lMutable), const float&);
}

View File

@ -24,11 +24,44 @@ private Q_SLOTS:
void baseClass();
void catchAll();
// TODO: sync / async
void functionPtrHandlers();
void stdFunctionHandlers();
void stdBindHandlers();
void lambdaHandlers();
};
QTEST_MAIN(tst_qpromise_fail)
#include "tst_fail.moc"
namespace {
const QString kErr = "0.42";
const float kRes = 0.42f;
const float kFail = -1.f;
float fnNoArg() { return kErr.toFloat(); }
float fnArgByVal(QString e) { return e.toFloat(); }
float fnArgByRef(const QString& e) { return e.toFloat(); }
class Klass {
public: // STATICS
static float kFnNoArg() { return kErr.toFloat(); }
static float kFnArgByVal(QString e) { return e.toFloat(); }
static float kFnArgByRef(const QString& e) { return e.toFloat(); }
public:
Klass(float v) : m_v{v} {}
float fnNoArg() const { return m_v; }
float fnArgByVal(QString v) const { return v.toFloat() + m_v; }
float fnArgByRef(const QString& v) const { return v.toFloat() + m_v; }
private:
const float m_v;
};
} // namespace
void tst_qpromise_fail::sameType()
{
// http://en.cppreference.com/w/cpp/error/exception
@ -87,3 +120,125 @@ void tst_qpromise_fail::catchAll()
QCOMPARE(error, QString("bar"));
}
void tst_qpromise_fail::functionPtrHandlers()
{
{ // Global functions.
auto p0 = QPromise<float>::reject(kErr).fail(&fnNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(&fnArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(&fnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // Static member functions.
auto p0 = QPromise<float>::reject(kErr).fail(&Klass::kFnNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(&Klass::kFnArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(&Klass::kFnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
}
// https://github.com/simonbrunel/qtpromise/issues/29
void tst_qpromise_fail::stdFunctionHandlers()
{
{ // lvalue.
std::function<float()> stdFnNoArg = fnNoArg;
std::function<float(QString)> stdFnArgByVal = fnArgByVal;
std::function<float(const QString&)> stdFnArgByRef = fnArgByRef;
auto p0 = QPromise<float>::reject(kErr).fail(stdFnNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(stdFnArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(stdFnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // const lvalue.
const std::function<float()> stdFnNoArg = fnNoArg;
const std::function<float(QString)> stdFnArgByVal = fnArgByVal;
const std::function<float(const QString&)> stdFnArgByRef = fnArgByRef;
auto p0 = QPromise<float>::reject(kErr).fail(stdFnNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(stdFnArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(stdFnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // rvalue.
auto p0 = QPromise<float>::reject(kErr).fail(std::function<float()>{fnNoArg});
auto p1 = QPromise<float>::reject(kErr).fail(std::function<float(QString)>{fnArgByVal});
auto p2 = QPromise<float>::reject(kErr).fail(std::function<float(const QString&)>{fnArgByRef});
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
}
//// https://github.com/simonbrunel/qtpromise/issues/29
void tst_qpromise_fail::stdBindHandlers()
{
using namespace std::placeholders;
const float val{42.f};
const Klass obj{val};
const std::function<float()> bindNoArg = std::bind(&Klass::fnNoArg, &obj);
const std::function<float(QString)> bindArgByVal = std::bind(&Klass::fnArgByVal, &obj, _1);
const std::function<float(const QString&)> bindArgByRef = std::bind(&Klass::fnArgByRef, &obj, _1);
auto p0 = QPromise<float>::reject(kErr).fail(bindNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(bindArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(bindArgByRef);
QCOMPARE(waitForValue(p0, kFail), val);
QCOMPARE(waitForValue(p1, kFail), val + kRes);
QCOMPARE(waitForValue(p2, kFail), val + kRes);
}
void tst_qpromise_fail::lambdaHandlers()
{
{ // lvalue.
auto lambdaNoArg = []() { return kRes; };
auto lambdaArgByVal = [](QString v) { return v.toFloat(); };
auto lambdaArgByRef = [](const QString& v) { return v.toFloat(); };
auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(lambdaArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // const lvalue.
const auto lambdaNoArg = []() { return kRes; };
const auto lambdaArgByVal = [](QString v) { return v.toFloat(); };
const auto lambdaArgByRef = [](const QString& v) { return v.toFloat(); };
auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal);
auto p2 = QPromise<float>::reject(kErr).fail(lambdaArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // rvalue.
auto p0 = QPromise<float>::reject(kErr).fail([]() { return kRes; });
auto p1 = QPromise<float>::reject(kErr).fail([](QString v) { return v.toFloat(); });
auto p2 = QPromise<float>::reject(kErr).fail([](const QString& v) { return v.toFloat(); });
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
}

View File

@ -7,6 +7,8 @@
#include "../../shared/utils.h"
#include <functional>
// QtPromise
#include <QtPromise>
@ -25,12 +27,44 @@ private Q_SLOTS:
void rejectSync();
void rejectAsync();
void skipResult();
void noHandler();
void nullHandler();
void functionPtrHandlers();
void stdFunctionHandlers();
void stdBindHandlers();
void lambdaHandlers();
};
QTEST_MAIN(tst_qpromise_then)
#include "tst_then.moc"
namespace {
const float kRes = 0.42f;
const float kFail = -1.f;
float fnNoArg() { return kRes; }
float fnArgByVal(float v) { return v; }
float fnArgByRef(const float& v) { return v; }
class Klass {
public: // STATICS
static float kFnNoArg() { return kRes; }
static float kFnArgByVal(float v) { return v; }
static float kFnArgByRef(const float& v) { return v; }
public:
Klass(float v) : m_v{v} {}
float fnNoArg() const { return m_v; }
float fnArgByVal(float v) const { return v + m_v; }
float fnArgByRef(const float& v) const { return v + m_v; }
private:
const float m_v;
};
} // namespace
void tst_qpromise_then::resolveSync()
{
QVariantList values;
@ -115,7 +149,7 @@ void tst_qpromise_then::skipResult()
QCOMPARE(value, 43);
}
void tst_qpromise_then::noHandler()
void tst_qpromise_then::nullHandler()
{
{ // resolved
auto p = QPromise<int>::resolve(42).then(nullptr);
@ -130,3 +164,125 @@ void tst_qpromise_then::noHandler()
QCOMPARE(p.isRejected(), true);
}
}
void tst_qpromise_then::functionPtrHandlers()
{
{ // Global functions.
auto p0 = QtPromise::resolve().then(&fnNoArg);
auto p1 = QtPromise::resolve(kRes).then(&fnArgByVal);
auto p2 = QtPromise::resolve(kRes).then(&fnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // Static member functions.
auto p0 = QtPromise::resolve().then(&Klass::kFnNoArg);
auto p1 = QtPromise::resolve(kRes).then(&Klass::kFnArgByVal);
auto p2 = QtPromise::resolve(kRes).then(&Klass::kFnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
}
// https://github.com/simonbrunel/qtpromise/issues/29
void tst_qpromise_then::stdFunctionHandlers()
{
{ // lvalue.
std::function<float()> stdFnNoArg = fnNoArg;
std::function<float(float)> stdFnArgByVal = fnArgByVal;
std::function<float(const float&)> stdFnArgByRef = fnArgByRef;
auto p0 = QtPromise::resolve().then(stdFnNoArg);
auto p1 = QtPromise::resolve(kRes).then(stdFnArgByVal);
auto p2 = QtPromise::resolve(kRes).then(stdFnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // const lvalue.
const std::function<float()> stdFnNoArg = fnNoArg;
const std::function<float(float)> stdFnArgByVal = fnArgByVal;
const std::function<float(const float&)> stdFnArgByRef = fnArgByRef;
auto p0 = QtPromise::resolve().then(stdFnNoArg);
auto p1 = QtPromise::resolve(kRes).then(stdFnArgByVal);
auto p2 = QtPromise::resolve(kRes).then(stdFnArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // rvalue.
auto p0 = QtPromise::resolve().then(std::function<float()>{fnNoArg});
auto p1 = QtPromise::resolve(kRes).then(std::function<float(float)>{fnArgByVal});
auto p2 = QtPromise::resolve(kRes).then(std::function<float(const float&)>{fnArgByRef});
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
}
//// https://github.com/simonbrunel/qtpromise/issues/29
void tst_qpromise_then::stdBindHandlers()
{
using namespace std::placeholders;
const float val{42.f};
const Klass obj{val};
const std::function<float()> bindNoArg = std::bind(&Klass::fnNoArg, &obj);
const std::function<float(float)> bindArgByVal = std::bind(&Klass::fnArgByVal, &obj, _1);
const std::function<float(const float&)> bindArgByRef = std::bind(&Klass::fnArgByRef, &obj, _1);
auto p0 = QtPromise::resolve().then(bindNoArg);
auto p1 = QtPromise::resolve(kRes).then(bindArgByVal);
auto p2 = QtPromise::resolve(kRes).then(bindArgByRef);
QCOMPARE(waitForValue(p0, kFail), val);
QCOMPARE(waitForValue(p1, kFail), val + kRes);
QCOMPARE(waitForValue(p2, kFail), val + kRes);
}
void tst_qpromise_then::lambdaHandlers()
{
{ // lvalue.
auto lambdaNoArg = []() { return kRes; };
auto lambdaArgByVal = [](float v) { return v; };
auto lambdaArgByRef = [](const float& v) { return v; };
auto p0 = QtPromise::resolve().then(lambdaNoArg);
auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal);
auto p2 = QtPromise::resolve(kRes).then(lambdaArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // const lvalue.
const auto lambdaNoArg = []() { return kRes; };
const auto lambdaArgByVal = [](float v) { return v; };
const auto lambdaArgByRef = [](const float& v) { return v; };
auto p0 = QtPromise::resolve().then(lambdaNoArg);
auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal);
auto p2 = QtPromise::resolve(kRes).then(lambdaArgByRef);
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
{ // rvalue.
auto p0 = QtPromise::resolve().then([]() { return kRes; });
auto p1 = QtPromise::resolve(kRes).then([](float v) { return v; });
auto p2 = QtPromise::resolve(kRes).then([](const float& v) { return v; });
QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes);
QCOMPARE(waitForValue(p2, kFail), kRes);
}
}