GNOME Bugzilla – Bug 164852
non extern "C" callbacks
Last modified: 2018-05-22 12:05:54 UTC
glibmm has several callback functions that we give to glib, where they are defined as extern "C" functions, but most of ours are not extern "C". The SUN Forte compiler warns about this and the Tru64 compiler calls it an error when using its "strict_ansi" option. This might get more important in future. Unfortunately, most of these callbacks are static member functions, which can not be extern "C". Changing them to separate functions means declaring them as friend functions [1] to the class, and, because of the need to declare functions before declaring them as friends, we often have to expose these functions as public API, without the help of a private: or protected: keyword. [1]: Though we could put these functions into an anonymous namespace, to prevent them being exported as public API, we then have to way to refer to that namespace in the "friend void some_function(int)" friend declaration. The attached patch fixes some of this, as described, but it is not pretty.
Created attachment 36347 [details] [review] externc.patch Fixes half of the extern "C" problems, often badly.
I can confirm that I have run into this exact problem. The error message from the compiler is similar to: cxx: Error: iochannel.cc, line 112: a value of type "GIOStatus (*)(GIOChannel *, char *, gsize, gsize *, GError **)" cannot be used to initialize an entity of type "GIOStatus (*)(GIOChannel *, gchar *, gsize, gsize *, GError **) C" &GlibmmIOChannel::io_read, --^
Tim, what platform is that? With all compilers (g++, MSVC++, SUN, IRIX, Tru64, AIX) that I've tried recently, the error can be avoided if you don't use some compiler option. The SUN compiler always gives a warning.
Sorry, I just noticed your question today. I was confirming the problem on Tru64 UNIX, with the `strict_ansi' option to the vendor cxx compiler.
Created attachment 353742 [details] [review] patch: Extern C without friend functions This patch shows how to call a private static member function from a function with "C" linkage without declaring the C function as a friend. All the ugly code is added in the .cc file, nothing in the .h file. The trick is to let the extern "C" function call the member function via a function pointer, which is initialized from another member function. If we really must separate extern "C" and extern "C++" functions, it would required a _lot_ more fixes. We would also have to decide if it's acceptable to use glib's function pointer types, like GClassInitFunc and GInstanceInitFunc, in glibmm's public API. I've done so in Glib::ExtraClassInit's constructor, for instance. The example code in ExtraClassInit's documentation wouldn't do. It shows how to pass pointers to extern "C++" functions to the constructor. Is this a real problem, a problem that we need to fix? I realize that it's a potential problem, but it looks to me as if it was more of a problem 12 years ago, when this bug report was filed, than it is now.
It's a real problem in the sense that it relies on non-Standard behaviour that just happens to exist in extant compilers, but may not always. And given how much attention is given to writing correct and idiomatic C++ in so many other areas of the mm projects, it would be nice if this would follow suit. Of course as you indicated, whether it's _practically_ a problem is a different question - albeit, again, I suspect an unknowably open one: being non-Standard means compilers' results could change at any time. I doubt they'll go out of their way to break things without a really good reason... but they _could_.
I mean to include this link, which has some useful info: https://stackoverflow.com/questions/14395192/why-does-c11-not-support-declaring-extern-c-on-a-static-member-function plus another suggested way of working around this, which 'preserves' (emulates) the same call syntax.
I don't understand how we can use the technique in the stackoverflow post that you link to. The whole point of letting the callback function be a static member function is that it shall be able to access private and protected data members and methods in its class (e.g. Gtk::Application_Class) and in classes of which it's a friend (e.g. Gtk::Application). In the final example in the stackoverflow post, A::callback is a reference to a non-member function A_callback(). A_callback() can't access private and protected members of class A, unless it's a friend of A. My contribution in comment 5 shows how we can avoid declaring the callback functions as friends. Clarification: Gtk::Xyz_Class is a friend of Gtk::Xyz. The default handler of Gtk::Xyz::signal_abc() is Gtk::Xyz_Class::abc_callback().
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glibmm/issues/1.