如何在不使用移动构造函数的情况下用自定义构造函数初始化tuple
解决std::tuple无移动构造时的自定义构造初始化问题
可以实现,核心是利用std::piecewise_construct和std::forward_as_tuple,让tuple直接在自身内存空间中构造每个元素,完全避免临时对象的移动/拷贝操作。
原代码的问题
你当前的初始化方式fields(Fs{i}...)会先创建一个个临时的Fs对象,再尝试把这些临时对象移动或拷贝到tuple的元素位置。由于A的移动构造函数被删除,而临时对象是右值,编译器优先尝试调用移动构造,最终导致编译失败。
修改后的代码
#include <tuple> struct A { int i{}; A(int i) : i(i) {} A(A&&) = delete; }; struct B { int i{}; B(int i) : i(i) {} B(B&& b) : i(b.i) {} }; template <typename... Fs> struct Container { std::tuple<Fs...> fields; constexpr Container(int i) : fields(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple(i)...) {} }; int main() { Container<A, B> c{1}; }
方案原理
std::piecewise_construct是一个标记类型,告诉tuple要采用“分段构造”的方式初始化每个元素。std::forward_as_tuple(i)会把构造参数打包成一个转发tuple,tuple内部会将这些参数直接转发给对应元素的构造函数,直接在tuple的内存位置构造对象,不会产生任何临时对象,自然也就不需要依赖移动或拷贝构造函数。
如果后续需要给不同元素传递不同的构造参数,只需要调整每个std::forward_as_tuple的参数即可,比如:
// 假设A需要int,B需要double constexpr Container(int a_val, double b_val) : fields(std::piecewise_construct, std::forward_as_tuple(a_val), std::forward_as_tuple(b_val)) {}
内容的提问来源于stack exchange,提问作者king_nak
相关产品推荐
相关产品推荐

