为什么添加析构函数(甚至是空的)会破坏我的结构,该结构使用 ref 转发和折叠来保存 ref 或值的副本?
Why does adding a destructor (even empty) break my struct that uses ref forwarding and collapsing to hold either a ref or copy of a value?
我正在创建一个类来存储对对象的引用(如果在构造函数中给定一个左值(,如果给定一个右值,则存储一个副本。这很好,可以编译:
template <typename obj_t>
struct holder
{
obj_t obj;
template <typename obj_ref_t>
holder(obj_ref_t && o)
: obj(std::forward<obj_ref_t>(o))
{}
};
template <typename obj_t>
holder<obj_t> make_held(obj_t && o) {
return holder<obj_t>(std::forward<obj_t>(o));
}
但是,当我向类添加一个析构函数(甚至是空析构函数(时,我收到一个编译器错误:
Invalid instantiation of non-const reference of type "obj_t &" from an rvalue of type "holder<obj_t &>"
为什么添加析构函数会以某种方式调用构造函数调用以从已包装的对象创建包装的对象?
构造函数模板永远不能是复制/移动构造函数
template <typename obj_ref_t>
holder(obj_ref_t && o) // not a move constuctor
当析构函数定义不存在时,您将隐式定义的移动构造函数用于holder
。用户定义的析构函数的存在将禁止此隐式移动构造函数定义。
现在,唯一剩下的可行候选者是上面的转换构造函数模板,但如果obj_ref_t
的类型为holder<T>
,则不起作用,需要此构造函数来初始化make_held
的返回值。所以这样的调用失败了
auto h = make_held(42);
简而言之,不要定义析构函数,或者如果必须定义移动构造函数。
定义像您拥有的构造函数模板这样的构造函数模板时,请注意,在某些情况下,它们可能优于移动构造函数。关于这个问题,SO 上有很多答案,这里有一个描述了问题,并有一个约束构造函数模板的解决方案。
如果要使用 C++17 编译器编译代码,由于保证复制省略,即使使用析构函数定义也可以编译上述代码。
相关文章:
- 如何循环打印顶点结构
- 通过方法访问结构
- 对RValue对象调用的LValue ref限定成员函数
- 使用不带参数的函数访问结构元素
- 预处理器:插入结构名称中的前一个行号
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 孤立代码块在结构中引发异常
- 有什么方法可以遍历结构吗
- 将Ref对象作为类成员
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 无法将结构注册为增强几何体3D点
- 多成员Constexpr结构初始化
- C++将文本文件中的数据读取到结构数组中
- 如何重构类层次结构以避免菱形问题
- 如何在C++中序列化结构数据
- std::vector的包装器,使数组的结构看起来像结构的数组
- 没有为自己的结构调用列表推回方法
- 为什么添加析构函数(甚至是空的)会破坏我的结构,该结构使用 ref 转发和折叠来保存 ref 或值的副本?
- C++ 编程(由 ref 和 by val 的优势)查询?/ 编辑 byRef 以外的结构的方法