server: object: reduce SFINAE
Use C++20 Concepts to reduce SFINAE in object.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I22be05b28a30cabafc10ca4f0c9eef124a20bc7f
diff --git a/include/sdbusplus/server/object.hpp b/include/sdbusplus/server/object.hpp
index c3eaeea..c86598b 100644
--- a/include/sdbusplus/server/object.hpp
+++ b/include/sdbusplus/server/object.hpp
@@ -14,10 +14,6 @@
namespace object
{
-// Forward declaration.
-template <class... Args>
-struct object;
-
namespace details
{
@@ -25,121 +21,6 @@
template <class... Args>
struct compose;
-/** Template to identify if an inheritance is a "normal" type or a nested
- * sdbusplus::object.
- */
-template <class T>
-struct compose_inherit
-{
- // This is a normal type.
- using type = T;
-
- // Normal types need emit_added called, if possible.
- template <class S>
- static void maybe_emit_iface_added(S* obj)
- {
- if constexpr (has_emit_added<S>())
- {
- obj->S::emit_added();
- }
- }
-
- // Test if emit_added() exists in T return std::true_type.
- template <class S>
- static constexpr auto has_emit_added_helper(int)
- -> decltype(std::declval<S>().emit_added(), std::true_type{});
-
- // If the above test fails, fall back to this to return std::false_type
- template <class>
- static constexpr std::false_type has_emit_added_helper(...);
-
- // Invoke the test with an int so it first resolves to
- // has_emit_added_helper(int), and when it fails, it resovles to
- // has_emit_added_helper(...) thanks to SFINAE.
- // So the return type is std::true_type if emit_added() exists in T and
- // std::false_type otherwise.
- template <class S>
- using has_emit_added = decltype(has_emit_added_helper<S>(0));
-};
-
-/** Template specialization for the sdbusplus::object nesting. */
-template <class... Args>
-struct compose_inherit<object<Args...>>
-{
- // Unravel the inheritance with a recursive compose.
- using type = compose<Args...>;
-
- // Redirect the interface added to the composed parts.
- template <class T>
- static void maybe_emit_iface_added(T* obj)
- {
- obj->compose<Args...>::maybe_emit_iface_added();
- }
-};
-
-/** std-style _t alias for compose_inherit. */
-template <class... Args>
-using compose_inherit_t = typename compose_inherit<Args...>::type;
-
-/** Templates to allow multiple inheritance via template parameters.
- *
- * These allow an object to group multiple dbus interface bindings into a
- * single class.
- */
-template <class T, class... Rest>
-struct compose_impl : compose_inherit_t<T>, compose_impl<Rest...>
-{
- compose_impl(bus_t& bus, const char* path) :
- T(bus, path), compose_impl<Rest...>(bus, path)
- {}
-
- void maybe_emit_iface_added()
- {
- compose_inherit<T>::maybe_emit_iface_added(
- static_cast<compose_inherit_t<T>*>(this));
- compose_impl<Rest...>::maybe_emit_iface_added();
- }
-};
-
-/** Specialization for single element. */
-template <class T>
-struct compose_impl<T> : compose_inherit_t<T>
-{
- compose_impl(bus_t& bus, const char* path) : compose_inherit_t<T>(bus, path)
- {}
-
- void maybe_emit_iface_added()
- {
- compose_inherit<T>::maybe_emit_iface_added(
- static_cast<compose_inherit_t<T>*>(this));
- }
-};
-
-/** Default compose operation for variadic arguments. */
-template <class... Args>
-struct compose : compose_impl<Args...>
-{
- compose(bus_t& bus, const char* path) : compose_impl<Args...>(bus, path) {}
-
- friend struct compose_inherit<object<Args...>>;
-
- protected:
- void maybe_emit_iface_added()
- {
- compose_impl<Args...>::maybe_emit_iface_added();
- }
-};
-
-/** Specialization for zero variadic arguments. */
-template <>
-struct compose<>
-{
- compose(bus_t& /*bus*/, const char* /*path*/) {}
-
- protected:
- void maybe_emit_iface_added() {}
-};
-
} // namespace details
/** Class to compose multiple dbus interfaces and object signals.
@@ -267,8 +148,66 @@
} // namespace object
+// Type alias for object_t.
template <class... Args>
using object_t = object::object<Args...>;
+namespace object::details
+{
+
+/** Template to identify if an inheritance is a "normal" type or a nested
+ * sdbusplus::object.
+ */
+template <class T>
+struct compose_inherit
+{
+ // This is a normal type.
+ using type = T;
+};
+
+/** Template specialization for the sdbusplus::object nesting. */
+template <class... Args>
+struct compose_inherit<object<Args...>>
+{
+ // Unravel the inheritance with a recursive compose.
+ using type = compose<Args...>;
+};
+
+/** std-style _t alias for compose_inherit. */
+template <class... Args>
+using compose_inherit_t = typename compose_inherit<Args...>::type;
+
+template <class... Args>
+struct compose : compose_inherit_t<Args>...
+{
+ compose(bus_t& bus, const char* path) :
+ compose_inherit<Args>::type(bus, path)... {};
+
+ /** Call emit_added on all the composed types. */
+ void maybe_emit_iface_added()
+ {
+ (try_emit<compose_inherit_t<Args>>(), ...);
+ }
+
+ protected:
+ /** Call emit_added for an individual composed type. */
+ template <class T>
+ void try_emit()
+ {
+ // If T is a normal class with emit_added, call it.
+ if constexpr (requires(T t) { t.emit_added(); })
+ {
+ this->T::emit_added();
+ }
+ // If T is a recursive object_t, call its maybe_emit_iface_added.
+ if constexpr (requires(T t) { t.maybe_emit_iface_added(); })
+ {
+ this->T::maybe_emit_iface_added();
+ }
+ }
+};
+
+} // namespace object::details
+
} // namespace server
} // namespace sdbusplus