Hello all,
For the past couple of weeks I have been working on a template to hold two-dimensional arrays.
Right now I am puzzling over an indexing question.
There are many places in the template where I would like to use initializer_lists to refer to user-specified row and column ranges, particularly in member function arguments. A typical example would be a member function whose declaration would be along the lines of:
Code:
Array<Type>::some_function(std::initializer_list<int> columns, std::initializer_list<int> rows);
which could get called via
Code:
arrayInstance.some_function({3:4}, {5:8});
You get the idea.
I then got it into my head that it would be really nice to be able to use Matlab-style indexing to specify the last column, or the last row, in the Array object -- along the lines of
Code:
arrayInstance.some_function({3:4}, {5:END});
where END takes the value -1, and can be defined in Array, or somewhere else.
The way I have tackled this so far was to write myself an Indices PODS class with two elements to hold start and finish values, and a constructor-from-initializer_list that looks something like this:
Code:
Indices::Indices(std::initializer_list<int> range, int replace_value)
{
int const *it = range.begin();
start = (*it == END) ? replace_value : *it ; ++it;
finish = (*it == END) ? replace_value : *it ;
...
}
So the elements of "range" give the values of Indices::start and Indices::finish -- but if either of them are entered as END by the user, they will be replaced by replace_value. (The default value of replace_value is END, so Indices::start and Indices::finish will never change if it is omitted.)
I also defined an Indices::endset(int) function to do the same thing for existing Indices objects:
Code:
Indices::endset(int replace_value)
{
if (start == END) start = replace_value;
if (finish == END) finish = replace_value;
}
Using Indices::endset, you can code up Array::some_function by modifying the above signature to something like
Code:
Array<Type>::some_function(Indices columns, Indices rows)
{
columns.endset(this->M);
rows.endset(this->N);
...
}
This does work, and I've been able to use it in practice. However, it is klutzy. What I would really like to be able to do is have the Indices constructor handle value-replacements in "columns" and "rows", instead of needing to put calls to Indices::endset in every single Array<Type> member function that uses this approach.
The basic problem is that, when Array<Type>::some_function is called, there is no easy way of inserting Array<Type>::M and Array<Type>::N into the optional argument of the Indices constructor when "columns" and "rows" are being built. The Indices class needs somehow to get access to these, and know which one is being used, M or N. So it needs to have some sort of deeper connection to Array<Type>, but I don't know what that connection should be.
There must be some more elegant way of doing this. Any suggestions?
Thanks
Grumpulus