Protecting copy constructor with std::enable_if

Viewed 493

I've written a class to facilitate type erasure that has the following constructors:

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) {
    }
};

I want to rewrite the first non-default constructor to take a reference rather than a value (Runnable & runnable rather than Runnable runnable), but if I do that then copying with a non-const Envelope like so

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

invokes that constructor rather than the copy constructor, and I get a stack overflow.

I think I can prevent that constructor from being called when Runnable == Envelope with std::enable_if like so

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)) {
}

and it compiles fine (although it triggers some intellisense errors in Visual Studio 2015, which is mildly annoying), but it doesn't stop that constructor from being called with non-const Envelopes and triggering a stack overflow.

I'm not entirely sure what I'm doing wrong here.

3 Answers
Related