能否将不可复制不可移动对象放入std::variant中?
能否将不可复制、不可移动的对象放入std::variant中?
答案是:不能直接将完全不可复制、不可移动的对象放入std::variant中,以下通过代码示例说明原因:
编译失败的示例(对象不可复制、不可移动)
#include <iostream> #include <variant> #include <vector> struct T { int _x; T(int x) : _x(x) { std::cout << "constructed" << std::endl; } #if 0 T(const T& t) : _x(t._x) { std::cout << "copied" << std::endl; } T( T&& t) : _x(t._x) { std::cout << "moved" << std::endl; } #else T(const T& t) = delete; T(T&& t) = delete; #endif }; T make_t(){ return T(1); } int main() { std::variant<std::monostate,T> v; v.emplace<T>(make_t()); }
这段代码里,结构体T的拷贝构造函数和移动构造函数被显式删除。调用v.emplace<T>(make_t())时,std::variant需要把make_t()返回的临时对象移动或拷贝到自身内部存储,但由于没有可用的移动/拷贝构造函数,编译会直接失败。
编译通过的示例(对象支持复制、移动)
#include <iostream> #include <variant> #include <vector> struct T { int _x; T(int x) : _x(x) { std::cout << "constructed" << std::endl; } #if 1 T(const T& t) : _x(t._x) { std::cout << "copied" << std::endl; } T(T&& t) : _x(t._x) { std::cout << "moved" << std::endl; } #else T(const T& t) = delete; T(T&& t) = delete; #endif }; T make_t(){ return T(1); } int main() { std::variant<std::monostate,T> v; v.emplace<T>(make_t()); }
这里T提供了有效的拷贝构造函数和移动构造函数,std::variant可以通过移动操作将临时对象存入内部存储,因此编译正常通过。
补充说明
如果想在std::variant中使用不可复制、不可移动的对象,唯一可行的方式是直接在variant内部就地构造该对象——也就是通过emplace直接传递构造参数,而非传入已有的对象实例。比如把main中的代码改成:
v.emplace<T>(1);
此时std::variant会直接在内部存储中调用T(int)构造函数创建对象,不需要依赖拷贝或移动构造函数,这种情况下即使T的拷贝/移动构造函数被删除,代码也能正常编译运行。
内容的提问来源于stack exchange,提问作者bradgonesurfing
相关产品推荐
相关产品推荐

