aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2021-12-02 15:24:44 +0100
committerAlexey Rusakov <Kitsune-Ral@users.sf.net>2021-12-02 15:24:44 +0100
commitdc08fb9dfd474023084de9ce86f29f177ca52fdc (patch)
tree29cb5ab8a133bc46c4ccbee1cd369cd665525949
parentae0ad49f36e8ba5983839581302ed16ddbd75d5f (diff)
downloadlibquotient-dc08fb9dfd474023084de9ce86f29f177ca52fdc.tar.gz
libquotient-dc08fb9dfd474023084de9ce86f29f177ca52fdc.zip
Improve function_traits<>; split out from util.*
Quotient::function_traits<> did not support member functions in a proper way (i.e. the way std::invoke_result<> treats them, with the function's owning class represented as the first parameter). Now that I gained the skill and understanding in function_traits<> somewhat wicked machinery, I could properly support member functions. Overloads and generic lambdas are not supported but maybe we'll get to those one day.
-rw-r--r--CMakeLists.txt2
-rw-r--r--lib/events/event.h1
-rw-r--r--lib/function_traits.cpp53
-rw-r--r--lib/function_traits.h93
-rw-r--r--lib/qt_connection_util.h2
-rw-r--r--lib/util.cpp32
-rw-r--r--lib/util.h52
7 files changed, 150 insertions, 85 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index aa3b9c98..ca92699c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -125,6 +125,8 @@ endif ()
# Set up source files
list(APPEND lib_SRCS
lib/quotient_common.h
+ lib/function_traits.h
+ lib/function_traits.cpp
lib/networkaccessmanager.cpp
lib/connectiondata.cpp
lib/connection.cpp
diff --git a/lib/events/event.h b/lib/events/event.h
index ce737280..4d4bb16b 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -5,6 +5,7 @@
#include "converters.h"
#include "logging.h"
+#include "function_traits.h"
namespace Quotient {
// === event_ptr_tt<> and type casting facilities ===
diff --git a/lib/function_traits.cpp b/lib/function_traits.cpp
new file mode 100644
index 00000000..4ff427e4
--- /dev/null
+++ b/lib/function_traits.cpp
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "function_traits.h"
+
+// Tests for function_traits<>
+
+using namespace Quotient;
+
+int f_();
+static_assert(std::is_same<fn_return_t<decltype(f_)>, int>::value,
+ "Test fn_return_t<>");
+
+void f1_(int, float);
+static_assert(std::is_same<fn_arg_t<decltype(f1_), 1>, float>::value,
+ "Test fn_arg_t<>");
+
+struct Fo {
+ int operator()();
+ static constexpr auto l = [] { return 0.0f; };
+ bool memFn();
+ void constMemFn() const&;
+ double field;
+ const double field2;
+};
+static_assert(std::is_same_v<fn_return_t<Fo>, int>,
+ "Test return type of function object");
+static_assert(std::is_same_v<fn_return_t<decltype(Fo::l)>, float>,
+ "Test return type of lambda");
+static_assert(std::is_same_v<fn_arg_t<decltype(&Fo::memFn)>, Fo>,
+ "Test first argument type of member function");
+static_assert(std::is_same_v<fn_return_t<decltype(&Fo::memFn)>, bool>,
+ "Test return type of member function");
+static_assert(std::is_same_v<fn_arg_t<decltype(&Fo::constMemFn)>, const Fo&>,
+ "Test first argument type of const member function");
+static_assert(std::is_void_v<fn_return_t<decltype(&Fo::constMemFn)>>,
+ "Test return type of const member function");
+static_assert(std::is_same_v<fn_return_t<decltype(&Fo::field)>, double&>,
+ "Test return type of a class member");
+static_assert(std::is_same_v<fn_return_t<decltype(&Fo::field2)>, const double&>,
+ "Test return type of a const class member");
+
+struct Fo1 {
+ void operator()(int);
+};
+static_assert(std::is_same<fn_arg_t<Fo1>, int>(),
+ "Test fn_arg_t defaulting to first argument");
+
+template <typename T>
+static void ft(const std::vector<T>&);
+static_assert(
+ std::is_same<fn_arg_t<decltype(ft<double>)>, const std::vector<double>&>(),
+ "Test function templates");
diff --git a/lib/function_traits.h b/lib/function_traits.h
new file mode 100644
index 00000000..83b8e425
--- /dev/null
+++ b/lib/function_traits.h
@@ -0,0 +1,93 @@
+// SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include <functional>
+
+namespace Quotient {
+
+namespace _impl {
+ template <typename AlwaysVoid, typename>
+ struct fn_traits {};
+}
+
+/// Determine traits of an arbitrary function/lambda/functor
+/*!
+ * Doesn't work with generic lambdas and function objects that have
+ * operator() overloaded.
+ * \sa
+ * https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765
+ */
+template <typename T>
+struct function_traits
+ : public _impl::fn_traits<void, std::remove_reference_t<T>> {};
+
+// Specialisation for a function
+template <typename ReturnT, typename... ArgTs>
+struct function_traits<ReturnT(ArgTs...)> {
+ using return_type = ReturnT;
+ using arg_types = std::tuple<ArgTs...>;
+ // See also the comment for wrap_in_function() in qt_connection_util.h
+ using function_type = std::function<ReturnT(ArgTs...)>;
+};
+
+namespace _impl {
+ template <typename AlwaysVoid, typename>
+ struct fn_object_traits;
+
+ // Specialisation for a lambda function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_object_traits<void, ReturnT (ClassT::*)(ArgTs...)>
+ : function_traits<ReturnT(ArgTs...)> {};
+
+ // Specialisation for a const lambda function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_object_traits<void, ReturnT (ClassT::*)(ArgTs...) const>
+ : function_traits<ReturnT(ArgTs...)> {};
+
+ // Specialisation for function objects with (non-overloaded) operator()
+ // (this includes non-generic lambdas)
+ template <typename T>
+ struct fn_traits<decltype(void(&T::operator())), T>
+ : public fn_object_traits<void, decltype(&T::operator())> {};
+
+ // Specialisation for a member function in a non-functor class
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...)>
+ : function_traits<ReturnT(ClassT, ArgTs...)> {};
+
+ // Specialisation for a const member function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const>
+ : function_traits<ReturnT(const ClassT&, ArgTs...)> {};
+
+ // Specialisation for a constref member function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const&>
+ : function_traits<ReturnT(const ClassT&, ArgTs...)> {};
+
+ // Specialisation for a prvalue member function
+ template <typename ReturnT, typename ClassT, typename... ArgTs>
+ struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) &&>
+ : function_traits<ReturnT(ClassT&&, ArgTs...)> {};
+
+ // Specialisation for a pointer-to-member
+ template <typename ReturnT, typename ClassT>
+ struct fn_traits<void, ReturnT ClassT::*>
+ : function_traits<ReturnT&(ClassT)> {};
+
+ // Specialisation for a const pointer-to-member
+ template <typename ReturnT, typename ClassT>
+ struct fn_traits<void, const ReturnT ClassT::*>
+ : function_traits<const ReturnT&(ClassT)> {};
+} // namespace _impl
+
+template <typename FnT>
+using fn_return_t = typename function_traits<FnT>::return_type;
+
+template <typename FnT, int ArgN = 0>
+using fn_arg_t =
+ std::tuple_element_t<ArgN, typename function_traits<FnT>::arg_types>;
+
+} // namespace Quotient
diff --git a/lib/qt_connection_util.h b/lib/qt_connection_util.h
index 46294499..86593cc8 100644
--- a/lib/qt_connection_util.h
+++ b/lib/qt_connection_util.h
@@ -3,7 +3,7 @@
#pragma once
-#include "util.h"
+#include "function_traits.h"
#include <QtCore/QPointer>
diff --git a/lib/util.cpp b/lib/util.cpp
index 2dfb09a6..03ebf325 100644
--- a/lib/util.cpp
+++ b/lib/util.cpp
@@ -135,35 +135,3 @@ int Quotient::patchVersion()
{
return Quotient_VERSION_PATCH;
}
-
-// Tests for function_traits<>
-
-using namespace Quotient;
-
-int f_();
-static_assert(std::is_same<fn_return_t<decltype(f_)>, int>::value,
- "Test fn_return_t<>");
-
-void f1_(int, QString);
-static_assert(std::is_same<fn_arg_t<decltype(f1_), 1>, QString>::value,
- "Test fn_arg_t<>");
-
-struct Fo {
- int operator()();
- static constexpr auto l = [] { return 0.0f; };
-};
-static_assert(std::is_same<fn_return_t<Fo>, int>::value,
- "Test return type of function object");
-static_assert(std::is_same<fn_return_t<decltype(Fo::l)>, float>::value,
- "Test return type of lambda");
-
-struct Fo1 {
- void operator()(int);
-};
-static_assert(std::is_same<fn_arg_t<Fo1>, int>(),
- "Test fn_arg_t defaulting to first argument");
-
-template <typename T>
-static QString ft(T&&);
-static_assert(std::is_same<fn_arg_t<decltype(ft<QString>)>, QString&&>(),
- "Test function templates");
diff --git a/lib/util.h b/lib/util.h
index 13efb94b..97f0ecbc 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -189,58 +189,6 @@ inline auto merge(T1& lhs, const Omittable<T2>& rhs)
return true;
}
-namespace _impl {
- template <typename AlwaysVoid, typename>
- struct fn_traits {};
-}
-
-/// Determine traits of an arbitrary function/lambda/functor
-/*!
- * Doesn't work with generic lambdas and function objects that have
- * operator() overloaded.
- * \sa
- * https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765
- */
-template <typename T>
-struct function_traits
- : public _impl::fn_traits<void, std::remove_reference_t<T>> {};
-
-// Specialisation for a function
-template <typename ReturnT, typename... ArgTs>
-struct function_traits<ReturnT(ArgTs...)> {
- using return_type = ReturnT;
- using arg_types = std::tuple<ArgTs...>;
- // Doesn't (and there's no plan to make it) work for "classic"
- // member functions (i.e. outside of functors).
- // See also the comment for wrap_in_function() below
- using function_type = std::function<ReturnT(ArgTs...)>;
-};
-
-namespace _impl {
- // Specialisation for function objects with (non-overloaded) operator()
- // (this includes non-generic lambdas)
- template <typename T>
- struct fn_traits<decltype(void(&T::operator())), T>
- : public fn_traits<void, decltype(&T::operator())> {};
-
- // Specialisation for a member function
- template <typename ReturnT, typename ClassT, typename... ArgTs>
- struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...)>
- : function_traits<ReturnT(ArgTs...)> {};
-
- // Specialisation for a const member function
- template <typename ReturnT, typename ClassT, typename... ArgTs>
- struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const>
- : function_traits<ReturnT(ArgTs...)> {};
-} // namespace _impl
-
-template <typename FnT>
-using fn_return_t = typename function_traits<FnT>::return_type;
-
-template <typename FnT, int ArgN = 0>
-using fn_arg_t =
- std::tuple_element_t<ArgN, typename function_traits<FnT>::arg_types>;
-
inline constexpr auto operator"" _ls(const char* s, std::size_t size)
{
return QLatin1String(s, int(size));