This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


168. C linkage for static member functions

Section: 9.11  [dcl.link]     Status: NAD     Submitter: Darin Adler     Date: 9 Sep 1999

[Picked up by evolution group at October 2002 meeting.]

9.11 [dcl.link] paragraph 4 says,

A C language linkage is ignored for the names of class members and the member function types of class member functions.
This makes good sense, since C linkage names typically aren't compatible with the naming used for member functions at link time, nor is C language linkage function type necessarily compatible with the calling convention for passing this to a non-static member function.

But C language linkage type (not name) for a static member function is invaluable for a common programming idiom. When calling a C function that takes a pointer to a function, it's common to use a private static member function as a "trampoline" which retrieves an object reference (perhaps by casting) and then calls a non-static private member function. If a static member function can't have a type with C language linkage, then a global or friend function must be used instead. These alternatives expose more of a class's implementation than a static member function; either the friend function itself is visible at namespace scope alongside the class definition or the private member function must be made public so it can be called by a non-friend function.

Suggested Resolution: Change the sentence cited above to:

A C language linkage is ignored for the names of class members and the member function types of non-static class member functions.
The example need not be changed because it doesn't involve a static member function.

The following workaround accomplishes the goal of not exposing the class's implementation, but at the cost of significant superstructure and obfuscation:

    // foo.h
    extern "C" typedef int c_func(int);
    typedef int cpp_func(int);
    class foo
    {
    private:
      c_func* GetCallback();
      static int Callback(int);
    };

    // foo.cpp
    #include "foo.h"

    // A local pointer to the static member that will handle the callback.
    static cpp_func* cpp_callback=0;

    // The C function that will actually get registered.
    extern "C" int CFunk(int i)
    {
      return cpp_callback(i);
    }

    c_func* foo::GetCallback()
    {
      cpp_callback = &Callback;    // Only needs to be done once.
      return &CFunk;
    }

Rationale (10/99): The Standard correctly reflects the intent of the Committee.

Note (March, 2008):

The Evolution Working Group recommended closing this issue with no further consideration. See paper J16/07-0033 = WG21 N2173.