C++ 用g++;
以下代码使用g++4.8.1成功编译:C++ 用g++;,c++,gcc,c++11,g++,C++,Gcc,C++11,G++,以下代码使用g++4.8.1成功编译: int main() { int(*)(); } using P = int(*)(); using Q = int*; P; // warning only Q; // warning only int(*)(); // error (but only in clang) int*; // error int(*p)(); // ok int *q; // ok 它看起来像一个指向函数的指针的简单声明: int(*f)();
int main()
{
int(*)();
}
using P = int(*)();
using Q = int*;
P; // warning only
Q; // warning only
int(*)(); // error (but only in clang)
int*; // error
int(*p)(); // ok
int *q; // ok
它看起来像一个指向函数的指针的简单声明:
int(*f)();
它不是用Clang3.4和vc++2013编译的
这是一个编译器错误还是标准的一个黑暗的地方
使用g++4.8.1编译良好的类似奇怪代码段列表(更新):
int(*)()代码>
int(*)代码>
int(*){}代码>
int(*())代码>
-std=c++98-pedantic
相同,除了int(*){}代码>这是可以理解的;扩展初始值设定项列表仅适用于-std=c++11
更新2:如中所述,即使进行了初始化,它们仍然可以很好地编译,并且g++不会为它们生成任何程序集(无论是否进行初始化),即使没有启用任何优化:
int(*)()=0代码>
int(*)=0代码>
int(*){}=0代码>
int(*())=0代码>
更新3:我真的很惊讶地发现int(*)(=“你好,世界!”代码>也可以编译(而int(*p)(=“你好,世界!”;
当然不能编译)
更新4:这太棒了,但是int(*){}=Hello,world代码>编译良好。还有下面一段非常奇怪的代码:int(*){}()=-+*/%&^~,:$()[]{};代码>()
更新5:如中所述
这一点以及一些相关的语法问题正在作为gcc进行跟踪
根据C++标准(第7节声明的P<6)< /P>
6初始化声明器列表中的每个初始化声明器都包含
一个声明器id,它是该声明器声明的名称
init声明程序,因此是声明声明的名称之一
因此,这只是一个编译器错误
有效的代码可能看起来像示例(除了您显示的函数指针声明),尽管我不能用MS VC++2010编译它
int(*p){};
您用于测试的编译器似乎允许在没有声明器id的情况下进行声明
还应考虑第8.1节类型名称的以下段落
1显式指定类型转换,并作为的参数
sizeof、alignof、new或typeid,类型名称应为
明确规定。这可以通过类型id来完成,该类型id在语法上是
省略
实体的名称
我不确定这有多大帮助,但我尝试了以下方法(clang 3.3,g++4.8.1):
另一方面,在g++4.8.2和4.9.0中,一切都可以很好地编译。不幸的是,我没有叮当声3.4
非常粗略地说,声明[iso第7节]按顺序由以下部分组成:
可选前缀说明符(例如静态
,虚拟
)
基本类型(例如,constdouble
,vector
)
声明符(例如n
,*p
,a[7]
,f(int)
)
可选后缀函数说明符(例如const
,noexcept
)
可选初始值设定项或函数体(例如={1,2,3}
或{return 0;}
现在,声明器大致由一个名称和一些可选的声明器操作符组成[iso 8/4]
前缀运算符,例如:
*
(指针)
*const
(常量指针)
和
(左值参考)
&&
(右值参考)
auto
(函数返回类型,尾随时)
后缀运算符,例如:
[]
(阵列)
()
(函数)
->
(函数尾部返回类型)
上述运算符旨在反映它们在表达式中的用法。后缀运算符的绑定比前缀更紧,括号可用于更改它们的顺序:int*f()
是返回int
指针的函数,而int(*f)(
是返回int
指针的函数
也许我错了,但我认为这些运算符不能在没有名称的声明中。因此,当我们编写int*q;
时,int
是基本类型,*q
是由前缀运算符*
后跟名称q
组成的声明符。但是int*;
本身不能出现
另一方面,当我们使用Q=int*;
定义时,声明Q;
本身就可以了,因为Q
是基本类型。当然,因为我们没有声明任何内容,我们可能会得到错误或警告,具体取决于编译器选项,但这是一个不同的错误
以上只是我的理解。标准(如N3337)所说的是[iso 8.3/1]:
每个声明器只包含一个声明器id;它命名声明的标识符。声明器id中出现的非限定id应为简单标识符,但某些特殊函数的声明除外(12.3[用户定义转换]、12.4[析构函数]、13.5[重载运算符])以及模板专门化或部分专门化的声明(14.7)
(方括号中的注释是我的)。因此我理解int(*)();
应该是无效的,我不能说为什么它在clang和不同版本的g++中有不同的行为。您可以使用这个:查看程序集
int main()
{
int(*)() = 0;
return 0;
}
生成:
main:
pushq %rbp
movq %rsp, %rbp
movl $0, %eax
popq %rbp
ret
这相当于:intmain(){return
int main()
{
int (*p)() = 0;
return 0;
}
main:
pushq %rbp
movq %rsp, %rbp
movq $0, -8(%rbp)
movl $0, %eax
popq %rbp
ret