如果在构造函数中给定左值,我正在创建一个类来存储对对象的引用,如果给定右值,则存储一个拷贝。这很好并编译:
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);
简而言之,不要定义析构函数,或者如果必须定义移动构造函数。
当像您拥有的那样定义构造函数模板时,请注意,在某些情况下,它们可能比移动构造函数更受欢迎。关于这个,有很多答案,here's one描述问题并有约束构造函数模板的解决方案。
如果您要使用 C++17 编译器编译您的代码,由于 guaranteed copy elision,上述代码甚至可以使用析构函数定义进行编译。 .
关于c++ - 为什么添加一个析构函数(即使是空的)会破坏我使用引用转发和折叠来保存引用或值拷贝的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51899406/