Use if constexpr (C++17 feature)

This commit is contained in:
Mat Sutcliffe
2021-04-17 21:57:20 +01:00
parent 5d67cd9f68
commit d7a461ff7a
11 changed files with 103 additions and 189 deletions

View File

@@ -57,10 +57,8 @@ namespace BlackMisc
result = true;
eventLoop.quit();
});
if (checkInit(init))
{
return true;
}
if constexpr (std::is_void_v<decltype(init())>) { init(); }
else if (init()) { return true; }
if (timeoutMs > 0)
{
QTimer::singleShot(timeoutMs, &eventLoop, &QEventLoop::quit);
@@ -68,20 +66,6 @@ namespace BlackMisc
eventLoop.exec();
return result;
}
private:
template <typename F>
static bool checkInit(F init, std::enable_if_t<std::is_void_v<decltype(init())>, int> = 0)
{
init();
return false;
}
template <typename F>
static bool checkInit(F init, std::enable_if_t<!std::is_void_v<decltype(init())>, int> = 0)
{
return init();
}
};
} // ns

View File

@@ -82,26 +82,19 @@ namespace BlackMisc
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, THasPushBack<T>());
if constexpr (THasPushBack<T>::value)
{
return makeOutputIterator([&container](auto &&v) { container.push_back(std::forward<decltype(v)>(v)); });
}
else
{
return makeOutputIterator([&container](auto &&v) { container.insert(std::forward<decltype(v)>(v)); });
}
}
/*!

View File

@@ -102,12 +102,6 @@ namespace BlackMisc
QString convertToQString(bool i18n = false) const;
private:
/*
* Templates used by the constructor template:
*/
template <typename T>
struct tag {};
template <typename T>
static const CLogCategoryList &fromClass()
{
@@ -115,27 +109,15 @@ namespace BlackMisc
static const auto list = []
{
CLogCategoryList list;
list.appendCategoriesFromMemberFunction(tag<T>(), THasGetLogCategories<T>());
list.appendCategoriesFromMetaType(tag<T>(), std::bool_constant<QMetaTypeId<T>::Defined>());
list.appendCategoriesFromMetaObject(tag<T>(), std::is_base_of<QObject, T>());
if constexpr (THasGetLogCategories<T>::value) { list.push_back(fromQStringList(T::getLogCategories())); }
if constexpr (QMetaTypeId<T>::Defined) { list.push_back(QMetaType::typeName(qMetaTypeId<T>())); }
if constexpr (std::is_base_of_v<QObject, T>) { list.appendCategoriesFromMetaObject(T::staticMetaObject); }
if (list.isEmpty()) { list.push_back(CLogCategories::uncategorized()); }
return list;
}();
return list;
}
template <typename T>
void appendCategoriesFromMemberFunction(tag<T>, std::true_type) { push_back(fromQStringList(T::getLogCategories())); }
void appendCategoriesFromMemberFunction(...) {}
template <typename T>
void appendCategoriesFromMetaType(tag<T>, std::true_type) { push_back(QMetaType::typeName(qMetaTypeId<T>())); }
void appendCategoriesFromMetaType(...) {}
template <typename T>
void appendCategoriesFromMetaObject(tag<T>, std::true_type) { appendCategoriesFromMetaObject(T::staticMetaObject); }
void appendCategoriesFromMetaObject(...) {}
void appendCategoriesFromMetaObject(const QMetaObject &);
};
}

View File

@@ -70,12 +70,9 @@ namespace BlackMisc
template <typename T, typename Flags>
static bool membersEqual(const T &a, const T &b, Flags)
{
return membersEqual(a, b, std::bool_constant<static_cast<bool>(Flags::value & CaseInsensitiveComparison)>());
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive) == 0; }
else { return a == b; }
}
template <typename T>
static bool membersEqual(const T &a, const T &b, std::true_type) { return a.compare(b, Qt::CaseInsensitive) == 0; }
template <typename T>
static bool membersEqual(const T &a, const T &b, std::false_type) { return a == b; }
};
/*!
@@ -135,15 +132,14 @@ namespace BlackMisc
template <typename T, typename Flags>
static bool membersLess(bool &io_greaterThan, const T &a, const T &b, Flags)
{
using CaseInsensitive = std::bool_constant<static_cast<bool>(Flags::value & CaseInsensitiveComparison)>;
if (io_greaterThan) { return false; }
io_greaterThan = membersLess(b, a, CaseInsensitive());
return membersLess(a, b, CaseInsensitive());
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison))
{
io_greaterThan = b.compare(a, Qt::CaseInsensitive) < 0;
return a.compare(b, Qt::CaseInsensitive) < 0;
}
else { io_greaterThan = b < a; return a < b; }
}
template <typename T>
static bool membersLess(const T &a, const T &b, std::true_type) { return a.compare(b, Qt::CaseInsensitive) < 0; }
template <typename T>
static bool membersLess(const T &a, const T &b, std::false_type) { return a < b; }
};
/*!
@@ -171,15 +167,10 @@ namespace BlackMisc
template <typename T, typename Flags>
static int membersCompare(const T &a, const T &b, Flags)
{
using CaseInsensitive = std::bool_constant<static_cast<bool>(Flags::value & CaseInsensitiveComparison)>;
return membersCompare(a, b, CaseInsensitive(), THasCompare<T, T>());
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive); }
else if constexpr (THasCompare<T, T>::value) { return compare(a, b); }
else { return a < b ? -1 : b < a ? 1 : 0; }
}
template <typename T, typename U>
static int membersCompare(const T &a, const T &b, std::true_type, U) { return a.compare(b, Qt::CaseInsensitive); }
template <typename T>
static int membersCompare(const T &a, const T &b, std::false_type, std::true_type) { return compare(a, b); }
template <typename T>
static int membersCompare(const T &a, const T &b, std::false_type, std::false_type) { return a < b ? -1 : b < a ? 1 : 0; }
};
} // Mixin

View File

@@ -26,27 +26,6 @@ namespace BlackMisc
*/
class LosslessTag {};
// *INDENT-OFF*
namespace Private
{
//! \cond PRIVATE
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void marshallMember(QDBusArgument &arg, const T &value, std::false_type) { value.marshallToDbus(arg); }
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void marshallMember(QDBusArgument &arg, const T &value, std::true_type) { value.marshallToDbus(arg, LosslessTag()); }
template <class T, std::enable_if_t<!THasMarshallMethods<T>::value, int> = 0>
void marshallMember(QDBusArgument &arg, const T &value, std::false_type) { arg << value; }
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void unmarshallMember(const QDBusArgument &arg, T &value, std::false_type) { value.unmarshallFromDbus(arg); }
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void unmarshallMember(const QDBusArgument &arg, T &value, std::true_type) { value.unmarshallFromDbus(arg, LosslessTag()); }
template <class T, std::enable_if_t<!THasMarshallMethods<T>::value, int> = 0>
void unmarshallMember(const QDBusArgument &arg, T &value, std::false_type) { arg >> value; }
//! \endcond
}
// *INDENT-ON*
namespace Mixin
{
/*!
@@ -95,8 +74,16 @@ namespace BlackMisc
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
meta.forEachMember([ &, this ](auto member)
{
using lossless = std::bool_constant<member.has(MetaFlags<LosslessMarshalling>())>;
Private::marshallMember(arg, member.in(*this->derived()), lossless());
const auto &value = member.in(*this->derived());
if constexpr (THasMarshallMethods<std::decay_t<decltype(value)>>::value)
{
if constexpr (member.has(MetaFlags<LosslessMarshalling>()))
{
value.marshallToDbus(arg, LosslessTag());
}
else { value.marshallToDbus(arg); }
}
else { arg << value; }
});
}
@@ -107,8 +94,16 @@ namespace BlackMisc
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
meta.forEachMember([ &, this ](auto member)
{
using lossless = std::bool_constant<member.has(MetaFlags<LosslessMarshalling>())>;
Private::unmarshallMember(arg, member.in(*this->derived()), lossless());
auto &value = member.in(*this->derived());
if constexpr (THasMarshallMethods<std::decay_t<decltype(value)>>::value)
{
if constexpr (member.has(MetaFlags<LosslessMarshalling>()))
{
value.unmarshallFromDbus(arg, LosslessTag());
}
else { value.unmarshallFromDbus(arg); }
}
else { arg >> value; }
});
}

View File

@@ -70,15 +70,18 @@ namespace BlackMisc
const Derived *derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T, std::enable_if_t<std::is_default_constructible_v<T>, int> = 0>
QVariant myself() const { return QVariant::fromValue(*derived()); }
template <typename T, std::enable_if_t<std::is_default_constructible_v<T>, int> = 0>
void myself(const QVariant &variant) { *derived() = variant.value<T>(); }
template <typename T, std::enable_if_t<! std::is_default_constructible_v<T>, int> = 0>
QVariant myself() const { qFatal("isMyself should have been handled before reaching here"); return {}; }
template <typename T, std::enable_if_t<! std::is_default_constructible_v<T>, int> = 0>
void myself(const QVariant &) { qFatal("isMyself should have been handled before reaching here"); }
template <typename T>
QVariant myself() const
{
if constexpr (std::is_default_constructible_v<T>) { return QVariant::fromValue(*derived()); }
else { qFatal("isMyself should have been handled before reaching here"); return {}; }
}
template <typename T>
void myself(const QVariant &variant)
{
if constexpr (std::is_default_constructible_v<T>) { *derived() = variant.value<T>(); }
else { qFatal("isMyself should have been handled before reaching here"); }
}
template <typename T>
QVariant basePropertyByIndex(const T *base, CPropertyIndexRef index) const { return base->propertyByIndex(index); }

View File

@@ -31,31 +31,6 @@
namespace BlackMisc
{
class CPropertyIndex;
namespace Private
{
//! \private
template <class T, class X>
int compareByProperty(const T &a, const T &b, const CPropertyIndex &index, std::true_type, X)
{
return a.comparePropertyByIndex(index, b);
}
//! \private
template <class T>
int compareByProperty(const T &a, const T &b, const CPropertyIndex &index, std::false_type, std::true_type)
{
return compare(a.propertyByIndex(index), b.propertyByIndex(index));
}
//! \private
template <class T>
int compareByProperty(const T &, const T &, const CPropertyIndex &, std::false_type, std::false_type)
{
qFatal("Not implemented");
return 0;
}
}
/*!
* Property index. The index can be nested, that's why it is a sequence
* (e.g. PropertyIndexPilot, PropertyIndexRealname).
@@ -153,7 +128,15 @@ namespace BlackMisc
return [index = *this](const auto & a, const auto & b)
{
using T = std::decay_t<decltype(a)>;
return Private::compareByProperty(a, b, index, THasComparePropertyByIndex<T>(), THasPropertyByIndex<T>());
if constexpr (THasComparePropertyByIndex<T>::value)
{
return a.comparePropertyByIndex(index, b);
}
else if constexpr (THasPropertyByIndex<T>::value)
{
return compare(a.propertyByIndex(index), b.propertyByIndex(index));
}
else { qFatal("Not implemented"); return 0; }
};
}

View File

@@ -17,31 +17,6 @@
namespace BlackMisc
{
class CPropertyIndexRef;
namespace Private
{
//! \private
template <class T, class X>
int compareByProperty(const T &a, const T &b, const CPropertyIndexRef &index, std::true_type, X)
{
return a.comparePropertyByIndex(index, b);
}
//! \private
template <class T>
int compareByProperty(const T &a, const T &b, const CPropertyIndexRef &index, std::false_type, std::true_type)
{
return compare(a.propertyByIndex(index), b.propertyByIndex(index));
}
//! \private
template <class T>
int compareByProperty(const T &, const T &, const CPropertyIndexRef &, std::false_type, std::false_type)
{
qFatal("Not implemented");
return 0;
}
}
/*!
* Non-owning reference to a CPropertyIndex with a subset of its features.
*/
@@ -205,7 +180,15 @@ namespace BlackMisc
return [index = *this](const auto & a, const auto & b)
{
using T = std::decay_t<decltype(a)>;
return Private::compareByProperty(a, b, index, THasComparePropertyByIndex<T>(), THasPropertyByIndex<T>());
if constexpr (THasComparePropertyByIndex<T>::value)
{
return a.comparePropertyByIndex(index, b);
}
else if constexpr (THasPropertyByIndex<T>::value)
{
return compare(a.propertyByIndex(index), b.propertyByIndex(index));
}
else { qFatal("Not implemented"); return 0; }
};
}

View File

@@ -151,12 +151,12 @@ namespace BlackMisc
protected:
//! Efficiently compare addresses of two objects. Return false if types are not compatible.
//! @{
template <typename T, typename U, std::enable_if_t<TIsEqualityComparable<const T *, const U *>::value, int> = 0>
static bool equalPointers(const T *a, const U *b) { return a == b; }
template <typename T, typename U, std::enable_if_t<! TIsEqualityComparable<const T *, const U *>::value, int> = 0>
static bool equalPointers(const T *, const U *) { return false; }
//! @}
template <typename T, typename U>
static bool equalPointers(const T *a, const U *b)
{
if constexpr (TIsEqualityComparable<const T *, const U *>::value) { return a == b; }
else { return false; }
}
private:
Derived &derived() { return static_cast<Derived &>(*this); }

View File

@@ -171,7 +171,7 @@ namespace BlackMisc
}
virtual int getMetaTypeId() const override
{
return maybeGetMetaTypeId(std::bool_constant<QMetaTypeId<T>::Defined> {});
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); } else { return QMetaType::UnknownType; }
}
virtual const void *upCastTo(const void *object, int metaTypeId) const override
{
@@ -205,9 +205,6 @@ namespace BlackMisc
static const T &cast(const void *object) { return *static_cast<const T *>(object); }
static T &cast(void *object) { return *static_cast<T *>(object); }
static int maybeGetMetaTypeId(std::true_type) { return qMetaTypeId<T>(); }
static int maybeGetMetaTypeId(std::false_type) { return QMetaType::UnknownType; }
};
//! \private Explicit specialization for the terminating case of the recursive CValueObjectMetaInfo::upCastTo.
@@ -236,22 +233,26 @@ namespace BlackMisc
template <typename T>
void maybeRegisterMetaListConvert(...) {}
template <typename T, bool IsRegisteredMetaType /* = true */>
struct MetaTypeHelperImpl
{
static constexpr int maybeGetMetaTypeId() { return qMetaTypeId<T>(); }
static void maybeRegisterMetaType() { qRegisterMetaType<T>(); qDBusRegisterMetaType<T>(); qRegisterMetaTypeStreamOperators<T>(); registerMetaValueType<T>(); maybeRegisterMetaListConvert<T>(0); }
};
template <typename T>
struct MetaTypeHelperImpl<T, /* IsRegisteredMetaType = */ false>
struct MetaTypeHelper
{
static constexpr int maybeGetMetaTypeId() { return QMetaType::UnknownType; }
static void maybeRegisterMetaType() {}
static constexpr int maybeGetMetaTypeId()
{
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); }
else { return QMetaType::UnknownType; }
}
static void maybeRegisterMetaType()
{
if constexpr (QMetaTypeId<T>::Defined)
{
qRegisterMetaType<T>();
qDBusRegisterMetaType<T>();
qRegisterMetaTypeStreamOperators<T>();
registerMetaValueType<T>();
maybeRegisterMetaListConvert<T>(0);
}
}
};
template <typename T>
using MetaTypeHelper = MetaTypeHelperImpl<T, QMetaTypeId<T>::Defined>;
//! \endcond
}
}

View File

@@ -211,7 +211,11 @@ namespace BlackMisc
static CWorker *fromTask(QObject *owner, const QString &name, F &&task)
{
int typeId = qMetaTypeId<std::decay_t<decltype(std::forward<F>(task)())>>();
return fromTaskImpl(owner, name, typeId, [task = std::forward<F>(task)]() mutable { return fromResultOf(std::move(task), 0); });
return fromTaskImpl(owner, name, typeId, [task = std::forward<F>(task)]() mutable
{
if constexpr (std::is_void_v<decltype(task())>) { std::move(task)(); return QVariant(); }
else { return QVariant::fromValue(std::move(task)()); }
});
}
//! Connects to a functor to which will be passed the result when the task is finished.
@@ -255,11 +259,6 @@ namespace BlackMisc
CWorker(const std::function<QVariant()> &task) : m_task(task) {}
static CWorker *fromTaskImpl(QObject *owner, const QString &name, int typeId, const std::function<QVariant()> &task);
template <typename F>
static auto fromResultOf(F &&func, std::enable_if_t<std::is_void_v<decltype(func())>, int>) { func(); return QVariant(); }
template <typename F>
static auto fromResultOf(F &&func, std::enable_if_t<!std::is_void_v<decltype(func())>, int>) { return QVariant::fromValue(func()); }
template <typename R>
R resultNoWait() { Q_ASSERT(m_result.canConvert<R>()); return m_result.value<R>(); }