c++ - 为什么添加一个析构函数(即使是空的)会破坏我使用引用转发和折叠来保存引用或值拷贝的结构?

标签 c++ c++11 templates perfect-forwarding

如果在构造函数中给定左值,我正在创建一个类来存储对对象的引用,如果给定右值,则存储一个拷贝。这很好并编译:

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/

相关文章:

c++ - 为什么找到 2 个不同大小的排序数组的中位数需要 O(log(min(n,m)))

c++ - QThread中的QTcpSocket将commitTransaction但是当调用Write时 "Cannot create children for a parent that is in a different thread."

c++ - 将 Scala 转换为 C++ - 将列表转换为 vector

c++ - 指向任意类方法的模板非类型指针

c++ - 如何在编译时从作用域运算符中提取类型?

c++ - 两种模板示例的区别是什么?

swift - Xcode 项目模板和 Swift 包依赖

c++ - 由于 Unresolved external 问题,OpenCV 无法编译 -- LNK2019

c++ - 需要帮助解码这个 typedef

mongoDB c++11驱动程序获取插入文档的ID