Hello!

Yongsheng found a problem in the C++ D-Bus binding, triggered by this
code:

void Session::activate()
{
    static GDBusMethodTable methods[] = {
...
        makeMethodEntry<ReadOperations,
                        bool,
                        ReadOperations::Config_t &,
                        typeof(&ReadOperations::getConfig), 
&ReadOperations::getConfig>
                        ("GetConfig"),

ReadOperations is a private base class of Session, which was meant to
inherit the implementation without writing any glue code.

The problem is that the "void *data" pointer is a "Session *" for all
interface methods, but the methodFunction template for getConfig casts
from void * to ReadOperations, which is incorrect.

I have been unhappy with the need to repeat method parameter types as
template parameters of makeMethodEntry. It would be much more natural to
write:
        makeMethodEntry(this,
                        &ReadOperations::getConfig>
                        "GetConfig")

A traits class which hinges on the type of the second parameter then
could provide the result of the call. The "this" pointer is passed so
that its type is known and the cast can be generated correctly.

I gave this a try and think it should work - except that g++ 4.3 and 4.4
crash when the type case is enabled in methodFunction2. Without that
line, the code compiles. Darn. If anyone has an idea how to make this
work with existing compilers, feel free to help me out.

Yongsheng, in the meantime please work around the problem by writing
some glue code (Session::getConfig, Session::getReports, ...). I don't
want to make the makeMethodEntry<> calls any more complex while there
still is a chance to make them simpler.

-- 
Best Regards, Patrick Ohly

The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.

diff --git a/src/gdbus/gdbus-cxx-bridge.h b/src/gdbus/gdbus-cxx-bridge.h
index f076177..251852c 100644
--- a/src/gdbus/gdbus-cxx-bridge.h
+++ b/src/gdbus/gdbus-cxx-bridge.h
@@ -5257,4 +5257,69 @@ GDBusMethodTable makeMethodEntry(const char *name, GDBusMethodFlags flags = GDBu
     return entry;
 }
 
+template <class T, class M, M m>
+struct MakeMethodEntry
+{
+    // There is no generic implementation of this method.
+    // If you get an error about it missing, then write
+    // a specialization for your type M (the method pointer).
+    //
+    // static GDBusMethodTable make(const char *name,
+    //                              GDBusMethodFlags flags)
+};
+
+template <class T,
+          class I,
+          void (I::*m)()>
+DBusMessage *methodFunction2(DBusConnection *conn,
+                             DBusMessage *msg, void *data)
+{
+    try {
+        // the next line triggers an internal compiler error in
+        // g++ 4.3 and 4.4 :-(
+        ((static_cast<T *>(data))->*m)();
+
+        DBusMessage *reply = dbus_message_new_method_return(msg);
+        if (!reply)
+            return NULL;
+        return reply;
+    } catch (...) {
+        return handleException(msg);
+    }
+}
+
+/** no return value, no parameters */
+template <class T, class B, void (B::*m)()>
+struct MakeMethodEntry<T, void (B::*)(), m>
+{
+    static GDBusMethodTable make(const char *name,
+                                 GDBusMethodFlags flags)
+    {
+        GDBusMethodTable entry;
+        entry.name = strdup(name);
+        std::string buffer;
+        entry.signature = strdup(buffer.c_str());
+        buffer.clear();
+        entry.reply = strdup(buffer.c_str());
+        entry.function = methodFunction2<T, B, m>;
+        entry.flags = flags;
+        return entry;
+    }
+};
+
+/**
+ * @param t            "this" pointer of the interface instance
+ * @param m            method pointer, either of T or a base class of T
+ * @param name         D-Bus method name, string must remain valid
+ * @param flags        additional flags for the method
+ */
+template <class T, class M> GDBusMethodTable makeMethodEntry2(T *t,
+                                                              M m,
+                                                              const char *name,
+                                                              GDBusMethodFlags flags = GDBusMethodFlags(0))
+{
+    // pick a specialization of the MakeMethodEntry class which fits M
+    return MakeMethodEntry<T, M, m>::make(name, flags);
+}
+
 #endif // INCL_GDBUS_CXX_BRIDGE
diff --git a/src/gdbus/test/example.cpp b/src/gdbus/test/example.cpp
index e8be227..edfcaa2 100644
--- a/src/gdbus/test/example.cpp
+++ b/src/gdbus/test/example.cpp
@@ -73,6 +73,8 @@ class Test {
     }
 
 public:
+    void simple() {}
+
     void method(std::string &text)
     {
         text = "Hello World";
@@ -218,9 +220,13 @@ public:
                             typeof(&Test::array), &Test::array>
                             ("Array"),
             makeMethodEntry<Test, typeof(&Test::error), &Test::error>("Error"),
+            makeMethodEntry2(this, &Test::simple, "Simple"),
             { },
         };
 
+        // DBusMessage* (*m)(DBusConnection*, DBusMessage*, void*) =
+        //    methodFunction<DBusTest, Test, &Test::simple>;
+
         static GDBusSignalTable signals[] = {
             signal.makeSignalEntry("Signal"),
             { },
_______________________________________________
SyncEvolution mailing list
[email protected]
http://lists.syncevolution.org/listinfo/syncevolution

Reply via email to