Reputation: 398
I have lot of code like this
MyClass v = {1,2,3,4,5,6};
Unfortunately my project is targeted stupid ARM compiler that does not support fancy C++11 features, in particular it doesn't support 'initialyzer_list'. Currently the only solution looks like this:
MyClass v(6);
v[0]=1;
v[1]=2;
...
The problem it that there is lot of code like above and manual editing is disaster. Any way to overcome it with less blood? Macro, library, nice trick, anything else that can be allow find-replace-regexp with some coding in MyClass?
Upvotes: 2
Views: 636
Reputation: 632
As a slight alternative to Ryan Haining's solution above, you don't actually need to put the array in a variable the line before:
#include <iostream>
struct A {
template<size_t N>
A(const int (&list)[N]) {
size = N;
myArr = new int[N];
int *tmp = myArr;
for(const int *i = list; i < list + N; ++i) {
*tmp++ = *i;
}
}
~A() {
delete[] myArr;
}
int *myArr;
size_t size;
};
int main(int argc, char **argv) {
A a = (int[]) {1, 2, 3, 4, 5};
for(int i = 0; i < a.size; ++i) {
std::cout << a.myArr[i] << std::endl;
}
return 0;
}
Because of copy elision and implicit constructors, you can get away with just a cast on the same line. The array is implicitly converted to your type, and then the temp value is moved to the stack dynamic storage efficiently through copy elision. This means revising your code would just require a couple of (type[])
and reworking your constructors to be array based instead of initializer_list based. Unfortunately, without c++11 foreach loops this can be a little annoying, but with some pointer works it's not awful, and you can always make some convenience macros like:
#define FOREACH(type, name, arr, N)\
for(type *__foreach__ptr__ = arr, (name) = *__foreach__ptr__;\
__foreach__ptr__ < (arr) + (N);\
++__foreach__ptr__, (name) = *__foreach__ptr__)
which would be used like:
int N = 5;
int arr[N] = {1, 2, 3, 4, 5};
FOREACH(int, val, arr, N) {
std::cout << val << std::endl;
}
Upvotes: 0
Reputation: 36882
If you can stand to declare the list as an array a line earlier, you can get the size as a template argument:
class MyClass {
public:
template <std::size_t N>
MyClass(const int (&in)[N]);
};
int main() {
static const int arr[] = {1,2,3,4,5,6};
MyClass mc(arr);
}
Upvotes: 3
Reputation: 275936
template<class T>
struct span {
T* b;
T* e;
span( T* s, T* f ):b(s), e(f) {}
T* begin() const { return b; }
T* end() const { return e; }
std::size_t size() const { return end()-begin(); }
};
template<class T, std::size_t N>
struct chain_array {
T arr[N];
T const& operator[](std::size_t i) const {return arr[i];}
std::size_t size() const { return N; }
T const* begin() const { return arr; }
T const* end() const { return arr+N; }
operator span<T>() const {
return span<T>(begin(), end());
}
chain_array<T, N+1> operator,( T rhs ) {
chain_array<T, N+1> r;
for (std::size_t i=0; i < N; ++i)
r[i]=(*this)[i];
r[N] = rhs;
return r;
}
};
template<class T>
chain_array<T, 1> chain( T t ) {
chain_array<T, 1> r;
r[0] = t;
return r;
}
now write this:
MyClass v = (chain(1),2,3,4,5,6);
and add an overload of MyClass::MyClass(span<T>)
.
This solution is inefficient because I create the intermediate arrays, and they are not discarded until the end of the line. A smart compiler could fix this.
We could create a chain of pointers or references (basically, an expression template) which we only collapse when we cast to the final il<T>
type if we cared.
Upvotes: 2