结构化绑定与std::tie():数组已存在变量赋值的替代方案咨询
好问题!这确实是C++里原生数组和std::tuple在赋值逻辑上的一个容易让人困惑的差异点。我们先搞清楚为什么std::tie对数组无效,再给你几个简洁的替代方案。
为什么std::tie对数组不起作用?
std::tie返回的是一个由引用组成的tuple,它的赋值运算符只支持接收tuple-like类型(比如std::tuple、std::pair、std::array这类能被结构化绑定识别的类型)。但原生C数组并不属于这个范畴——数组名在表达式中会退化为指针,没法直接和std::tie返回的tuple完成赋值匹配,所以std::tie(x1,y1,z1) = a会报错。而std::tuple本身就是tuple-like类型,所以对应的赋值能正常工作。
简洁的替代方案
方案1:C++20及以上用std::to_array配合std::tie
这是最接近std::tie写法的方案,利用C++20新增的std::to_array把原生数组转换成std::array(tuple-like类型),然后就能用std::tie赋值了:
// 假设x1、y1、z1已经存在 std::tie(x1, y1, z1) = std::to_array(a);
方案2:C++17及以上用临时std::array包装
如果你的编译器还不支持C++20,可以手动把数组元素塞进临时std::array里:
std::tie(x1, y1, z1) = std::array{a[0], a[1], a[2]};
这种写法虽然要写索引,但比挨个x1=a[0]; y1=a[1]; z1=a[2];要紧凑一些。
方案3:用std::apply批量赋值(C++17+)
std::apply可以对tuple-like类型的每个元素执行操作,我们可以结合临时std::array来实现批量赋值:
std::apply([&](auto& e1, auto& e2, auto& e3) { x1 = e1; y1 = e2; z1 = e3; }, std::array{a[0], a[1], a[2]});
如果是C++20,同样可以换成std::to_array(a)来简化。
方案4:封装辅助函数(通用场景)
如果你需要频繁给原生数组做这种赋值,可以自己写一个简单的辅助函数,用法和std::tie一样简洁:
#include <type_traits> template <typename T, size_t N, typename... Args> std::enable_if_t<N == sizeof...(Args)> assign_from_array(T (&arr)[N], Args&... args) { size_t idx = 0; ((args = arr[idx++]), ...); // 折叠表达式遍历赋值 } // 使用时直接这样写: assign_from_array(a, x1, y1, z1);
总结
如果不想挨个写数组索引,以上几种方案都能满足你的需求:C20首选std::to_array+std::tie;C17可以用临时std::array;频繁使用的话,封装辅助函数是最方便的。当然,如果一开始就能用std::array代替原生数组,那后续的赋值操作会和std::tuple一样顺畅~
内容的提问来源于stack exchange,提问作者oz1cz

