c++ - 使用 std::enable_if 保护复制构造函数

标签 c++ c++11 templates template-meta-programming typetraits

我编写了一个类来促进具有以下构造函数的类型删除:

class Envelope {
public:
    Envelope() {}

    template<typename Runnable>
    Envelope(Runnable runnable)
        : m_runFunc(&Envelope::RunAndDeleteRunnable<Runnable>), m_runnable(new Runnable(runnable)) {
    }

    template<typename Runnable>
    Envelope(Runnable * runnable)
        : m_runFunc(&Envelope::RunRunnable<Runnable>), m_runnable(runnable) {
    }
};

我想重写第一个非默认构造函数以获取引用而不是值(Runnable & runnable 而不是 Runnable runnable),但如果我这样做然后像这样用非常量 Envelope 复制

Envelope next(...);
Envelope otherNext(next);

调用该构造函数而不是复制构造函数,我得到堆栈溢出。

我想我可以在 Runnable == Envelopestd::enable_if 时阻止构造函数被调用,就像这样

template<typename Runnable = typename std::enable_if<std::negate<std::is_same<Runnable, Nova::Envelope>>::value, Runnable>::type>
Envelope(Runnable & runnable)
    : m_runFunc(&Envelope::RunAndDeleteRunnable<Runnable>), m_runnable(new Runnable(runnable)) {
}

并且它编译得很好(尽管它在 Visual Studio 2015 中触发了一些智能感知错误,这有点烦人),但它不会阻止使用非常量 Envelope 调用该构造函数和触发堆栈溢出。

我不完全确定我在这里做错了什么。

最佳答案

防止这种情况的最简单方法是添加一个“非 const”复制构造函数:

class Envelope {
public:
    Envelope() {}
    Envelope(const Envelope&) = default;
    Envelope(Envelope& e) : Envelope(const_cast<const Envelope&>(e)) {}
    ...
    }
};

您没有做任何特别错误的事情,只是当您编写采用一个模板化参数(或可变参数)的构造函数时,它们往往是“粘性的”并拦截用于复制构造函数的东西。在选择调用哪个函数时,复制构造函数没有得到我所知道的任何特殊处理。模板化函数更适合非常量对象。通过添加一个与非常量情况匹配的具体(非模板),现在该函数和模板之间的匹配度将保持一致。在平局的情况下,函数总是胜过模板。

关于c++ - 使用 std::enable_if 保护复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43928711/

相关文章:

c++ - 为什么模板只能在头文件中实现?

c++ - cpp 在标记之间插入额外的空间

c++ - 绑定(bind)返回值和可变参数模板

c++ - memory_order_relaxed 和原子 RMW 操作

c++ - 使用 `-> decltype` 推断返回类型

c++ - 如何在 C++ 中以毫秒为单位获取系统时间(不是自纪元以来)?

c++ - 我应该只对构造函数和移动运算符写 noexcept 吗?

c++ - 为某些模板参数设置模板函数的公共(public)/私有(private)

c++ - 性能与正确性/偏好?

c++ - 动态分配内存和取消引用