Protecting the copy constructor with std :: enable_if

I wrote a class to facilitate erasing styles, which 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 constructor, different from the standard one, instead of the link ( Runnable & runnable, not Runnable runnable), but if I do this, then copying using the non-constant Envelope/ p>

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

calls this constructor, not the copy constructor, and I get a stack overflow.

I think I can prevent this constructor from being called when Runnable== Envelopewith std::enable_ifso

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 causes some intellisense errors in Visual Studio 2015, which is slightly annoying), but it does not prevent the constructor from being called with a non-constant Envelopeand causing a stack overflow.

, .

+4
3
template<
  class Runnable,
  std::enable_if_t<
    !std::is_same<std::decay_t<Runnable>, Envelope>{},
    int
  > =0
>
Envelope(Runnable&& runnable) : 
  m_runFunc(&Envelope::RunAndDeleteRunnable<std::decay_t<Runnable>>),
  m_runnable(new std::decay_t<Runnable>(std::forward<Runnable>(runnable)))
{}

++ 14 style _t ; ++ 11, , typename .

. , Envelope .

std::decay_t "" Runnable Runnable&& .

, , new std::make_unique , raw-new raw .

.

+1

- "non const":

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

, , , , , ( ), , , "" , . , , . . ( ), , . .

+5

, -

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

- EDIT -

W.F. (),

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

because if you need two (or more) template constructors, they cannot differ only for the default template type parameter; WF solution to avoid this problem.

+3
source

Source: https://habr.com/ru/post/1676973/


All Articles