Class (and function) templates in C++ are special in that their entire definition needs to be known at the point of instantiation. That makes it near impossible to hide any implementation details. The documentation for CSimpleStringT tries to compensate for that by omitting the template non-type parameter that is strictly an implementation detail.
The true class template declaration (in atlsimpstr.h) is:
template< typename BaseType , bool t_bMFCDLL = false>
class CSimpleStringT
There are indeed two template parameters (with the second one having a default value), and client code needs to provide no more than two parameters to instantiate this class template.
Strictly speaking, though, the entire existence of CSimpleStringT
is an implementation detail. It surfaces, since it exposes some of the public API, inherited by CStringT (which, as you found out, instantiates its base class template using two template arguments).
CStringT
, still, is an implementation detail. Client code never uses it directly, but would rather use one of two concrete class template instantiations: CStringW
or CStringA
, for wide and ANSI character strings, respectively.
The important take-away here is: C++ class and function templates are powerful, yet impose unique challenges to documentation. Many concepts (like the CRTP) aren't reflected in source code at all, so there's no source location where you could place the documentation. At most other times you have to decide between documentation that's complete or documentation that's helpful. CSimpleStringT
opted for helpful (yet incomplete), where CStringT
decided to use complete (yet less than helpful) documentation.