I decided to implement Python's slice with C++ by myself. I wrote a function which accepts variadic slice_info<int>
arguments and returns the slice selection of an n-dimensional array, ndvalarray<T, D>
.
I compiled with Visual C++ 2015 and the code is like the following:
template<typename T>
struct slice_info {
T fr, to, step;
slice_info(T i) {
fr = 1; to = i; step = 1;
}
slice_info(std::initializer_list<T> il) {
std::vector<T> l(il);
if (l.size() == 1)
{
fr = 1; step = 1; to = l[0];
}
else if (l.size() == 2) {
fr = l[0]; step = 1; to = l[1];
}
else {
fr = l[0]; step = l[2]; to = l[1];
}
}
slice_info(const slice_info<T> & x) : fr(x.fr), to(x.to), step(x.step) {
}
};
template<typename T, int D>
void slice(const ndvalarray<T, D> & va, slice_info<int>&& s) {
// ndvalarray<T, D> is a n-dimensional array of type T
}
template<typename T, int D, typename ... Args>
void slice(const ndvalarray<T, D> & va, slice_info<int>&& s, Args&& ... args) {
slice(va, std::forward<Args>(args)...);
}
template<typename T, int D>
void slice_work_around(const ndvalarray<T, D> & va, const std::vector<slice_info<int>> & vs) {
}
int main(){
// Here is a 3-dimensional arr
ndvalarray<int, 3> arr;
// I want to get a slice copy of arr.
// For dimension 1, I select elements from position 1 to position 2.
// For dimension 2, I select elements from position 3 to position 6 stride 2
// For dimension 3, I select only the position 7 element
slice(arr, { 1, 2 }, { 3, 6, 2 }, {7}); // #1 error
slice(arr, { 1, 2 }, slice_info<int>{ 3, 6, 2 }, slice_info<int>{7}); // #2 yes
slice_work_around(arr, { {1, 2}, {3, 6, 2}, {7} }); // #3 yes
}
I thought #1 is an error because
braced-init-list is not an expression and therefore has no type
I tried #2 and #3, and they worked. However I am still wondering is there are possible ways to make #1 possible. This question is a bit similar with c11-variable-number-of-arguments-same-specific-type, and in my case these variable number of arguments are braced-init-list.
slice_info<T>
accepts a std::initializer_list<T>
, in order to describe a slice selection of a dimension, like std::slice()
. ndvalarray
has more than one dimension, so I have to give a pack of slice_info<T>
.
I choose to implement a constructor with a std::initializer_list<T>
argument, because I can use a braced-init-list, and I don't need to give T
or call constructors explicitly (like #2 does). Maybe it's a bad design, but I think it's simple to use.