As far as whether the technique is documented (and if you are doing this with C++11 or later, please use an enum class), it's a fairly common technique to template on an enum or a boolean and then do your specializations.
One clear difference is that with this technique, you obviously can't add more specializations without modifying the primary code. An enum (or enum class) only has so many values. That could be either a good or bad thing, depending on whether you want it to be centrally tracked. But that could easily be changed by templating on a class and encapsulating it, a third option which isn't quite this technique nor does it involve public inheritance.
This technique has its biggest advantage, IMHO, in that you have the option to implement things inline. For example:
template<e_Specialization e>
class TemplatedBase {
public:
void bar() {
// code
if (e == Specialization_A) {
...
}
// code
}
};
I see this a lot with classes that are known from the outset to be in a performance critical path. There could be a boolean variable that controls whether or not intrusive performance profiling occurs. Because these branches are known at compile time, they are trivially optimized. This is a good way to do it because you can still use both versions of the class in the same build (e.g. run unit tests on both).
Another difference compared to inheritance, is that derived classes can easily add state if they need to. This technique as it stands would require specializing the whole class to add state. Again, this could be good or bad; a more constrained design is good if you don't need to break those constraints. And you can easily change the design to enable adding extra state:
template <e_Specialization e>
struct ExtraState {};
template <e_Specialization e>
class TemplatedBase : private ExtraState<e> {
...
A third, minor example, is that you aren't exposing any inheritance relationship. This is mostly small, but remember that you can get things like slicing or even implicit reference/pointer conversion. This is a pretty strict win for this technique.
In sum I would say that:
- It's a win if you utilize the ability to implement something once and write the differences inline with no perf penalty
- It's a win if you want to be explicit in your design about there being a limited number of implementations.
If neither of those are true then the design is a bit unorthodox and a little more complex compared to just using inheritance, although it doesn't really have any strong technical disadvantage. So if you have a good number of junior devs around, this code might be harder to read.