为何初始化atomic对象时{}可行而()不可行?
std::atomic<stru>时双大括号{{}}可行,单大括号包裹的直接初始化({})却报错? 咱们先看你给出的示例代码:
#include <atomic> struct stru { int a{}; int b{}; }; int main() { // 无法运行:std::atomic<stru> as({}); std::atomic<stru> as{{}}; }
对应的错误信息是:
prog.cc: In function 'int main()':
prog.cc:9:26: error: call of overloaded 'atomic()' is ambiguous
std::atomicas({});
^
In file included from prog.cc:1:0:
/opt/wandbox/gcc-7.2.0/include/c++/7.2.0/atomic:200:17: note: candidate: std::atomic<_Tp>::atomic(_Tp) noexcept [with _Tp = stru]
atomic(_Tp __i) noexcept : _M_i(__i) { }
^~~~~
...(其他候选构造函数的提示)
问题根源:构造函数的重载歧义
这个报错的核心是编译器无法确定你要调用std::atomic<stru>的哪个构造函数。
当你写std::atomic<stru> as({});时,括号里的{}是一个空的初始化列表,此时编译器有两种合法的解读方式:
- 将
{}值初始化一个临时的stru对象,然后调用std::atomic<stru>的构造函数atomic(stru desired)(这个构造函数用于用一个stru实例初始化原子对象); - 将
{}当作聚合初始化的列表,直接初始化std::atomic<stru>的内部成员(因为std::atomic对于可平凡复制的T,通常被实现为聚合类型,包含一个T类型的成员)。
这两种解读都符合C++标准,所以编译器抛出了重载歧义的错误。
为什么双大括号{{}}能解决问题?
当你使用std::atomic<stru> as{{}};时,这是C++的嵌套列表初始化:
- 外层的
{}负责初始化std::atomic<stru>对象本身; - 内层的
{}明确指定用来初始化std::atomic<stru>内部的stru成员(或者传递给对应的构造函数)。
这种写法消除了歧义:编译器会明确将内层的{}用于初始化原子对象的底层值,要么触发聚合初始化,要么匹配接受stru的构造函数,不会再出现两种解读的冲突。
额外补充:C++版本的影响
需要注意的是,std::atomic的具体实现(是否为聚合类型)在不同C++版本中可能略有差异,但核心的初始化规则是一致的:双大括号的写法通过明确嵌套层级,避免了初始化列表的歧义解读。
内容的提问来源于stack exchange,提问作者Lingxi

