为何C++对象可赋值{}却无法与{}比较?相关问题解析
关于默认初始化对象比较的C++语法问题
默认构造的对象通常代表“已初始化但未存储值”的状态,例如默认构造的std::unique_ptr不指向任何对象(实际通过存储nullptr来表示该状态)。
默认初始化常通过赋值{}完成,但尝试通过s == {}判断对象是否为默认初始化状态时,代码无法编译:
struct S { S() = default; bool operator== (const S&) const { return false; } }; int main () { S s = {}; // 默认初始化 s = {}; // 赋值默认构造的对象 if (s == {}) // 检查's'是否包含值 ; }
编译错误信息如下:
x.cc:12:12: error: expected primary-expression before ‘{’ token 12 | if (s == {}) // 检查's'是否包含值 | ^
有人尝试为类添加bool operator== (const std::initializer_list<int>&);,但这也无法解决问题。以下是针对该场景的三个技术问题解答:
1. 为何s = {}中右侧能正确转换为默认构造对象,而s == {}却不行?
C++中不同语法上下文对{}的处理规则不同:
- 赋值表达式
s = {}属于赋值操作,右侧的{}会触发列表初始化规则:因为S存在默认构造函数,编译器会自动将{}隐式转换为临时的S对象,完成赋值。 - 而相等运算符
==的操作数必须是合法的表达式,{}本身并不是一个表达式,C++不允许在这种运算符操作数的位置直接用{}来隐式生成临时对象——必须显式写出S{}来生成一个完整的表达式,才能参与比较。
2. 为何添加bool operator== (const std::initializer_list<int>&);无济于事?
当写出s == {}时,编译器首先会检查右侧是否是合法的主表达式,而{}在这个上下文里不满足表达式要求,直接触发语法错误,根本不会进入重载解析阶段去匹配这个initializer_list版本的运算符。只有当上下文明确要求std::initializer_list类型时(比如函数参数明确声明为该类型),{}才会被解析为初始化列表。
3. 除了“标准不允许”外,是否存在不允许此类语法的设计理由?
核心原因是消除语法歧义与遵循显式优先原则:
- 若允许
== {}这种写法,编译器可能无法明确{}的意图:比如如果类同时拥有默认构造函数和接受std::initializer_list的构造函数,{}可能被解析为默认构造的临时对象,也可能被解析为空的初始化列表,导致歧义。 - C++设计强调“显式优于隐式”,要求显式写出
S{}能让代码意图更清晰,避免读者和编译器对代码逻辑产生误解,同时减少潜在的语法解析冲突。
内容的提问来源于stack exchange,提问作者Wolfgang Bangerth
相关产品推荐
相关产品推荐

