替代 initializer_list 之前的 C++11
Alternative to initializer_list prior C++11
我有很多这样的代码
MyClass v = {1,2,3,4,5,6};
不幸的是,我的项目是针对愚蠢的 ARM 编译器的,它不支持花哨的 C++11 功能,特别是它不支持 'initialyzer_list'。
目前唯一的解决方案是这样的:
MyClass v(6);
v[0]=1;
v[1]=2;
...
问题是,上面有很多代码和手动编辑是灾难。
有什么办法可以减少血量吗?
宏、库、绝妙的技巧,还有什么可以允许在 MyClass 中使用一些代码进行查找替换正则表达式?
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;
}
现在写这个:
MyClass v = (chain(1),2,3,4,5,6);
并添加 MyClass::MyClass(span<T>)
.
的重载
此解决方案效率低下,因为我创建了中间数组,并且它们直到行尾才被丢弃。聪明的编译器可以解决这个问题。
我们可以创建一个指针或引用链(基本上是一个表达式模板),如果我们关心的话,我们只会在转换为最终 il<T>
类型时才折叠它。
如果你能忍受在前面一行将列表声明为数组,你可以将大小作为模板参数获取:
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);
}
作为 Ryan Haining 上述解决方案的一个小替代方案,您实际上不需要将数组放入前一行的变量中:
#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;
}
由于复制省略和隐式构造函数,您只需在同一行进行强制转换即可。该数组被隐式转换为您的类型,然后通过复制省略将临时值有效地移动到堆栈动态存储。这意味着修改您的代码只需要几个 (type[])
并将您的构造函数重新设计为基于数组而不是基于 initializer_list。不幸的是,如果没有 c++11 的 foreach 循环,这可能会有点烦人,但有了一些指针工作,它并不可怕,而且你总是可以制作一些方便的宏,比如:
#define FOREACH(type, name, arr, N)\
for(type *__foreach__ptr__ = arr, (name) = *__foreach__ptr__;\
__foreach__ptr__ < (arr) + (N);\
++__foreach__ptr__, (name) = *__foreach__ptr__)
可以像这样使用:
int N = 5;
int arr[N] = {1, 2, 3, 4, 5};
FOREACH(int, val, arr, N) {
std::cout << val << std::endl;
}
我有很多这样的代码
MyClass v = {1,2,3,4,5,6};
不幸的是,我的项目是针对愚蠢的 ARM 编译器的,它不支持花哨的 C++11 功能,特别是它不支持 'initialyzer_list'。 目前唯一的解决方案是这样的:
MyClass v(6);
v[0]=1;
v[1]=2;
...
问题是,上面有很多代码和手动编辑是灾难。 有什么办法可以减少血量吗? 宏、库、绝妙的技巧,还有什么可以允许在 MyClass 中使用一些代码进行查找替换正则表达式?
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;
}
现在写这个:
MyClass v = (chain(1),2,3,4,5,6);
并添加 MyClass::MyClass(span<T>)
.
此解决方案效率低下,因为我创建了中间数组,并且它们直到行尾才被丢弃。聪明的编译器可以解决这个问题。
我们可以创建一个指针或引用链(基本上是一个表达式模板),如果我们关心的话,我们只会在转换为最终 il<T>
类型时才折叠它。
如果你能忍受在前面一行将列表声明为数组,你可以将大小作为模板参数获取:
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);
}
作为 Ryan Haining 上述解决方案的一个小替代方案,您实际上不需要将数组放入前一行的变量中:
#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;
}
由于复制省略和隐式构造函数,您只需在同一行进行强制转换即可。该数组被隐式转换为您的类型,然后通过复制省略将临时值有效地移动到堆栈动态存储。这意味着修改您的代码只需要几个 (type[])
并将您的构造函数重新设计为基于数组而不是基于 initializer_list。不幸的是,如果没有 c++11 的 foreach 循环,这可能会有点烦人,但有了一些指针工作,它并不可怕,而且你总是可以制作一些方便的宏,比如:
#define FOREACH(type, name, arr, N)\
for(type *__foreach__ptr__ = arr, (name) = *__foreach__ptr__;\
__foreach__ptr__ < (arr) + (N);\
++__foreach__ptr__, (name) = *__foreach__ptr__)
可以像这样使用:
int N = 5;
int arr[N] = {1, 2, 3, 4, 5};
FOREACH(int, val, arr, N) {
std::cout << val << std::endl;
}