The vnl_matrix documentation states that the contained type just has to have valid *,+,/, and - operators.
However, one also needs to create a new specialization of the vnl_numeric_traits template. Further, there are instances in the code of doing things like T(0) for a zero value and T(1) for a 1 value (which ignores the purpose of the numeric_traits specialization - because a type may or may not be directly convertible to an integer, and even if one can create it from an integer, there is no guarantee that T(0) is the additive identity or that T(1) is the multiplicative identity.) There are also instances in the code of passing objects of type T to vnl_math_isnan, vnl_math_isfinite and vnl_math_abs (which one would presumably have to overload). There are probably lots of other sneaky little uses that I didn't notice.
I am not sure what to say in making the documentation accurate. However, the portions in vnl_matrix.h and vnl_matrix.cxx about just declaring your own rational class and overloading *,+,/, and - should probably be removed until someone can look at the code and see what really does need to be overloaded.