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."
It's already indicated by @JerryCoffin's comment. The best way is to use the
static_assert
in a destructor. i.e.Since destructor can be only 1, it's guaranteed that the
static_assert
is checked whenever there is an instantiation of its object.IMO, another elegant way is to create a utility class & inherit the same, such as: