I’m implementing a multi-dimensional tensor for a linear algebra library in D and this is basically what I was aiming to for the base class:
class Tensor( T_scalar, T_dimensions ..., int T_storageOrder = StorageOrder.columnMajor )
{
}
In the idea, the user can define the characteristics of the tensor through template parameters and as a result I can deduce as many things as possible during compile-time, a bit like Eigen does.
Unfortunately the compiler is not so happy with that definition and triggers an error such as:
Tensor(T_scalar,T_args...,int T_storageOrder = StorageOrder.columnMajor) template tuple parameter must be last one
I’m not so sure why this restriction is in place but I ended up doing what I consider being a hack… basically, having defined the StorageOrder as an enum allows me to check if the last argument of the template tuple parameter matches one of the values from the enum, and if so I can use it to set the value of the StorageOrder for that tensor, otherwise I set it up with a default value.
enum StorageOrder : int
{
columnMajor = -1,
rowMajor = -2
}
class Tensor( T_scalar, T_args ... )
{
private:
alias TensorTraits!( T_scalar, T_args ) traits;
alias traits.dimensions T_dimensions;
alias traits.storageOrder T_storageOrder;
}
struct TensorTraits( T_scalar, T_args ... )
if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
static immutable auto dimensions = mixin( extractDataFromTemplateTupleParameter.dimensions );
static immutable int storageOrder = extractDataFromTemplateTupleParameter.storageOrder;
private:
static auto extractDataFromTemplateTupleParameter()
{
Tuple!( string, "dimensions", int, "storageOrder" ) templateTupleParameterData;
static if ( T_args[$ - 1] == StorageOrder.columnMajor || T_args[$ - 1] == StorageOrder.rowMajor )
{
alias TypeTuple!( T_args[0 .. $ - 1] ) dimensionsTuple;
templateTupleParameterData.storageOrder = T_args[$ - 1];
}
else
{
alias TypeTuple!( T_args ) dimensionsTuple;
templateTupleParameterData.storageOrder = StorageOrder.columnMajor;
}
static assert( dimensionsTuple.length > 0,
"No dimensions have been defined." );
foreach ( dimension; dimensionsTuple )
{
static assert( isIntegral!( typeof( dimension ) ),
"Dimensions sizes needs to be defined as integrals." );
static assert( dimension >= 0,
"Dimensions sizes cannot be negative." );
}
templateTupleParameterData.dimensions = dimensionsTuple.stringof;
return templateTupleParameterData;
}
}
static bool areTemplateParametersValid( T_scalar, T_args ... )()
{
static assert( isNumeric!( T_scalar ),
"The 'T_scalar' template argument is not a numeric type." );
static assert( T_args.length > 0,
"No dimensions have been defined." );
return true;
}
Since I’ve just started with D, and since I’m not so sure about this hack, I would like to know if this sounds good to you guys or if there’s maybe a better way of handling this?
FYI this is what I ended up doing.