C++中无法从atomic对象构造tuple的编译错误解决咨询
根本原因
std::atomic<T> 是不可拷贝的类型——它的拷贝构造函数和拷贝赋值运算符被显式删除了。这是因为原子对象的拷贝会破坏其原子性语义,C++标准禁止这种操作。当你调用 std::make_tuple(a1,a2,a3) 时,make_tuple 会尝试将传入的原子对象拷贝到新创建的 tuple 中,而这一操作不符合 std::atomic 的设计规则,因此编译报错。
解决方法
1. 存储原子对象的指针到 tuple
如果你需要保留原原子对象的所有权,同时在 tuple 中引用它们,可以将指针存入 tuple:
auto my_tuple = std::make_tuple(&a1, &a2, &a3);
此时 tuple 的类型为 std::tuple<std::atomic<double>*, std::atomic<double>*, std::atomic<double>*>,你可以通过解引用指针来访问原子对象:
// 读取第一个原子对象的值 double val = (*std::get<0>(my_tuple)).load();
2. 使用 std::reference_wrapper 存储引用
如果希望 tuple 直接持有原原子对象的引用(而非指针),可以用 std::ref 包装原子对象:
#include <functional> // 需要包含此头文件 auto my_tuple = std::make_tuple(std::ref(a1), std::ref(a2), std::ref(a3));
这种方式下,tuple 中的元素是对原原子对象的引用,修改 tuple 中的元素会直接影响原对象。注意:必须保证原原子对象的生命周期长于 tuple,否则会出现悬空引用问题。
3. 移动原子对象到 tuple(C++20 及以上)
从 C++20 开始,std::atomic 支持移动语义。如果你不再需要原原子对象,可以将它们移动到 tuple 中:
auto my_tuple = std::make_tuple(std::move(a1), std::move(a2), std::move(a3));
移动后,原原子对象处于有效但未指定的状态,不能再被使用。
4. 存储原子对象的值(而非原子对象本身)
如果你的需求只是获取原子对象当前的值,而非持有原子对象,可以先通过 load() 读取值,再存入 tuple:
auto my_tuple = std::make_tuple(a1.load(), a2.load(), a3.load());
此时 tuple 的类型为 std::tuple<double, double, double>,仅包含普通数值。
内容的提问来源于stack exchange,提问作者Pirate

