I'm looking through the Eigen source code for educational purposes. I've noticed that for each concrete class template X
in the hierarchy, there is an internal::traits<X>
defined. A typical example can be found in Matrix.h:
namespace internal {
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
struct traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
{
typedef _Scalar Scalar;
typedef Dense StorageKind;
typedef DenseIndex Index;
typedef MatrixXpr XprKind;
enum {
RowsAtCompileTime = _Rows,
ColsAtCompileTime = _Cols,
MaxRowsAtCompileTime = _MaxRows,
MaxColsAtCompileTime = _MaxCols,
Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret,
CoeffReadCost = NumTraits<Scalar>::ReadCost,
Options = _Options,
InnerStrideAtCompileTime = 1,
OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime
};
};
}
Now I understand traits to be a way of extending existing classes that you do not want to modify with extra information pertaining to some piece of new code. For example, a user of class template Foo<class TAllocator>
might want to make use of existing memory allocators FastAlloc
and AlignedAlloc
, but Foo needs to know how to interface with these two, and as such a FooTraits<AlignedAlloc>::allocate()
and FooTraits<FastAlloc>::allocate()
are defined by the user, which in turn are used by Foo
.
In this case, however, I don't readily see the problem with just specifying Scalar
in each derived class, i.e. have Matrix
define Matrix::Scalar
using a typedef in the class body. What is the advantage here of using a traits class? Is it just for the purposes of keeping the code clean, i.e. storing all relevant properties of each class in the traits class?
Edit as per Nicol Bolas's response: I understand that some of these typedefs might need to be kept "internal", i.e. should not be exposed to the user, which would explain the traits class. That seems to make sense, however some of these typedefs, such as Scalar
, are available to the outside world, through a typedef in the base class of Matrix
:
template<typename Derived> class MatrixBase
: public DenseBase<Derived>
{
public:
typedef MatrixBase StorageBaseType;
typedef typename internal::traits<Derived>::StorageKind StorageKind;
typedef typename internal::traits<Derived>::Index Index;
typedef typename internal::traits<Derived>::Scalar Scalar;
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
This brings us back to the original question: why isn't Scalar
just a typedef in Matrix
itself? Is there any reason aside from stylistic choice?
Matrix
inherits,MatrixBase
, publicly defines some of these typedefs, such asScalar
, which brings us back to the start - why not defineScalar
in Matrix to begin with? – Arabic