Provided that I have a C library containing a function declared as void g(void (*callback)());
The following code is elegant yet illegal:
struct A
{
// error C2159: more than one storage class specified (VC++ Nov 2012 CTP)
static extern "C" void callback()
{}
};
g(A::callback);
Why does C++11 not support this?
First, the function declaration is legal. The
extern "C"
, however, is ignored for class members, so ifg
expects anextern "C" void (*)()
, you can't pass itcallback
.As to the why of this, I suspect that originally, it was mainly a question of orthogonality: it makes no sense for a class member function to be
extern "C"
in general, and orthogonality (or simply no one considered the case of static members) means that this applies to static member functions as well, although allowing them to beextern "C"
would have been useful. Today (i.e. C++11), it would be problematic to change the rule, because it could break existing code. IMHO, the change would be acceptable, because the amount of code it would break is probably very small, and the breakage results in a compile time error—not a change in runtime semantics—so is easily detected and fixed. Still, as far as I know, no one made a proposal to change this, so it didn't get changed.This is a particularly confusing topic to wade into. Let's attack §7.5 "Linkage specifications" [dcl.link].
Note that the property of language linkage applies to two completely different kinds of entities: types and names.
A function has a generally-invisible bit of information in its type which identifies which ABI it conforms to: C calling conventions, Pascal, Fortran, all might be specified to use the stack in different ways, so calling them through a pointer requires knowing the invisible language-tag.
The name of a variable or function from another language can be accessed syntactically through C++, or from the other language referring to a C++ declaration. But not every language can match up with C++'s naming scheme and OO model. So interfaces in this scheme don't include classes.
Because these things are managed separately, it's possible to have something with different linkage in its type (calling conventions) and its name (linker symbol).
The
extern "C" {}
affects all function declarations, including pointers and references, except member functions. Since a function may only be defined in a namespace or as a member, C functions can only be defined at namespace scope.The standard gives an example here:
You can emulate the behavior you want using a
typedef
, though. From another example in §7.5/4,Combining these examples with yours, you can have
In practice, it seldom makes a difference. C and C++ use compatible calling conventions on most platforms (see Jonathan Wakely's comments on this page for exceptions), as long as you don't try to pass or return a non-POD C++ class type. This is a less-implemented feature of C++, due to the confusing overloading of terms and conceptual distinctions ranging from subtle to academic.