xml*_*lmx 15 c c++ static extern c++11
只要我有一个包含声明为void g(void (*callback)());的函数的C库以下代码是优雅但非法的:
struct A
{
// error C2159: more than one storage class specified (VC++ Nov 2012 CTP)
static extern "C" void callback()
{}
};
g(A::callback);
Run Code Online (Sandbox Code Playgroud)
为什么C++ 11不支持这个?
Pot*_*ter 16
这是一个特别令人困惑的话题.让我们攻击§7.5"链接规范"[dcl.link].
1)所有函数类型,具有外部链接的函数名称和具有外部链接的变量名称具有语言链接.
请注意,语言链接的属性适用于两种完全不同的实体:类型和名称.
函数在其类型中具有通常不可见的信息位,用于标识它符合的ABI:C调用约定,Pascal,Fortran,可以指定以不同方式使用堆栈,因此通过指针调用它们需要知道隐形语言标签.
来自另一种语言的变量或函数的名称可以通过C++语法访问,或者从引用C++声明的其他语言访问.但并非每种语言都能与C++的命名方案和OO模型相匹配.因此,此方案中的接口不包括类.
因为这些东西是分开管理的,所以可以在其类型(调用约定)和名称(链接符号)中使用不同的链接.
4)链接规范嵌套.当链接规范嵌套时,最里面的规则确定语言链接.链接规范不会建立范围.甲联动说明书应仅在命名空间范围(3.3)发生.在链接规范中,指定的语言链接适用于所有函数声明符的函数类型,具有外部链接的函数名称,以及在链接规范中声明的具有外部链接的变量名称.在确定类成员名称和类成员函数的函数类型的语言链接时,忽略AC语言链接.
将extern "C" {}影响所有函数声明,包括指针和引用,除非成员函数.由于函数只能在命名空间或成员中定义,因此只能在命名空间范围内定义C函数.
该标准在此给出了一个例子:
extern "C" typedef void FUNC_c();
class C {
// the name of the function mf1 and the member
// function’s type have C++ language linkage; the
// parameter has type pointer to C function
void mf1(FUNC_c*);
// the name of the function mf2 and the member
// function’s type have C++ language linkage
FUNC_c mf2;
// the name of the data member q has C++ language
// linkage and the data member’s type is pointer to
// C function
static FUNC_c* q;
};
Run Code Online (Sandbox Code Playgroud)
但是,您可以使用a模拟所需的行为typedef.从§7.5/ 4中的另一个例子来看,
extern "C" typedef void FUNC();
// the name f2 has C++ language linkage and the
// function’s type has C language linkage
FUNC f2;
Run Code Online (Sandbox Code Playgroud)
将这些示例与您的示例相结合,您就可以拥有
extern "C" typedef void callback_t();
callback_t A_callback; // declare function with C++ name and C type
struct A
{
static callback_t &callback; // not a member function
};
// in source file:
// definition matches semantics of declaration, although not syntax
void A_callback() { ... }
// define static member reference
callback_t &A::callback = A_callback;
g(A::callback); // call syntax is emulated
Run Code Online (Sandbox Code Playgroud)
在实践中,它很少有所作为.C和C++在大多数平台上使用兼容的调用约定(请参阅Jonathan Wakely在此页面上对异常的评论),只要您不尝试传递或返回非POD C++类类型即可.这是一个较少实现的C++特性,由于术语的过载和从微妙到学术的概念区别混乱.
首先,函数声明是合法的。extern "C"但是,类成员会忽略 ,因此如果需要g,
extern "C" void (*)()则无法传递它callback。
至于为什么会这样,我怀疑最初主要是一个正交性问题:类成员函数一般来说是没有意义的extern "C",而正交性(或者根本没有人考虑静态成员的情况)意味着:这也适用于静态成员函数,尽管允许它们是extern "C"有用的。如今(即 C++11),更改规则会出现问题,因为它可能会破坏现有代码。恕我直言,这种更改是可以接受的,因为它会破坏的代码量可能非常小,并且破坏会导致编译时错误(而不是运行时语义的更改),因此很容易检测和修复。不过,据我所知,没有人提出改变这一点的建议,所以它没有得到改变。