jeudi 29 décembre 2016

Ensuring a template class isn't polymorphic?

I was recently working on a C++ library where I was designing a template class that, for efficiency and safety reasons, needed to specifically be non-polymorphic. To ensure that later on I didn't forget this and accidentally break everything, I thought I'd be a good citizen and add a static assertion to that effect.

I initially tried something like this:

template <typename T> class VirtualVerboten {
     ...

     static_assert(!std::is_polymorphic<VirtualVerboten>::value,
                   "This should not be polymorphic."); // Error!
};

This doesn't compile because, at the time that I'm using VirtualVerboten, it's an incomplete type. If this were a non-template class, I'd just put the static_assert right after the type:

class NonTemplateVirtualVerboten {
   ...
}
static_assert(!std::is_polymorphic<NonTemplateVirtualVerboten>::value,
              "This should not be polymorphic.");

But since this is a template class, the analogous idea of making a "template static_assert" isn't legal:

template <typename T> class VirtualVerboten {
     ...

};

template <typename T>              
static_assert(!std::is_polymorphic<VirtualVerboten>::value,
              "This should not be polymorphic."); // Error!

The solution I came up with was to find a member function inside of VirtualVerboten that would likely be used when the template was instantiated (specifically, the constructor), then put the static assertion in there:

template <typename T> class VirtualVerboten {
     VirtualVerboten();
};

template <typename T>
VirtualVerboten<T>::VirtualVerboten() {
  static_assert(!std::is_polymorphic<VirtualVerboten>::value,
                "This should not be polymorphic."); // Yay!
  doSomeActualThingsAtRuntime();
}

This works, except that it relies on the fact that this particular constructor will actually be invoked and therefore instantiated, which fails if there are multiple constructors that could be called.

Is there a "foolproof" way to add this static assertion here? I understand why the original code was producing an error and why you can't have a template static assertion, so this is more of a "did I miss another way of doing this?" rather than a "here's why what you did doesn't work."

Aucun commentaire:

Enregistrer un commentaire