为什么c++ 中类内初始值不能使用圆括号初始化?而全局域中却可以
问题说明
class point{
int x(0);//error: expected identifier before numeric constantx86-64 gcc 15.1
};
int x(0);//正常初始化
int main() {
return 0;
}
网上搜索到的说法是无法和函数声明做区分,所以语法上规定函数内部的圆括号形式都是函数声明:
class Widget
{
private:
typedef int x;
int z(x);//函数声明,通过编译
};
class Widget
{
private:
int x;
int z(x);//error: 'x' is not a type
};
但是这不能很好的说服我,因为全局域这种情况语言是可以自己区分出是函数声明还是变量定义的:
typedef int x;
int fun(x);//函数声明
int y=0;
int variable(y);//变量定义
int fun(int x){
return x;
}
int main() {
std::cout<<fun(4);
return 0;
}
//通过编译
问题解决
在[N2756](N2756 - 非静态数据成员初始值设定项 — N2756 - Non-static data member initializers) "An issue raised in Kona regarding scope of identifiers:"部分找到了答案
产生语义无法区分的原因是“初始化器中标识符作用域允许使用类作用域,并带有前向查找的可能性” (即在初始化器中可以引用类中在初始化语句后定义的成员)
class S {
int i{x}; //编译通过,未报错
static int x; // x在此处声明
};
int variable(y);//error: 'y' was not declared in this scopex86-64 gcc
int y=0;
也就是说如果允许在类内使用圆括号初始化,真正无法区分的是下面两种情况,在读取到int i(x)语句时无法区分,有歧义
class Widget {
int x(y); // 这可能是:
// 1. 用y初始化x(如果y是变量)
// 2. 声明返回int、参数类型为y的函数x(如果y是类型)
// y的定义在后面
};
而在全局域中在解析初始化时是必须定义好的 也就是说为符号必须先声明后使用,下面这种情况本身是无法通过编译的:
int fun(x);//error: 'x' was not declared in this scopex86-64 gcc 15.1
typedef int x;
int variable(y);//error: 'y' was not declared in this scopex86-64 gcc
int y=0;
int main() {
return 0;
}
总结
- 初始化器允许在类作用域前向查找,导致初始化式中的符号类型(变量/类型)无法确定,无法在语法层面消除"成员函数声明"与"带初始化的成员变量"的歧义
- 而全局域中是解析初始化时是必须定义好,能够根据变量类型区分出是函数声明还是初始化,没有歧义。
而最终的解决方案是:保留初始化式允许在类作用域前向查找的特性,并通过语法上限制初始化器形式(= 和 {})避免语法歧义
类中所有形如 int x(y);都认为是函数声明,y必须是已声明的类型