C++ 使用实际元素初始化boost::multi_数组的干净方法
我正在寻找干净的语法糖来从显式值初始化C++ 使用实际元素初始化boost::multi_数组的干净方法,c++,boost,C++,Boost,我正在寻找干净的语法糖来从显式值初始化boost::multi_数组。我能想出的最好办法就是 double g[5][5] = { {-0.0009 , 0.003799 , 0.00666 , 0.00374 , 0.00186 }, {-0.0008 , 0.0176 , 0.0619 , 0.0159 , 0.00324 }, {0.00099 , 0.0475 , 0.666 , 0.037
boost::multi_数组。我能想出的最好办法就是
double g[5][5] = {
{-0.0009 , 0.003799 , 0.00666 , 0.00374 , 0.00186 },
{-0.0008 , 0.0176 , 0.0619 , 0.0159 , 0.00324 },
{0.00099 , 0.0475 , 0.666 , 0.0376 , 0.00758 },
{0.00242 , 0.02189 , 0.0624 , 0.0192 , 0.0008 },
{0.00182 , 0.00404 , 0.00479 , 0.00924 , 0.00189 }};
boost::multi_array_ref<double,2> mg((double*)g,boost::extents[5][5]);
double g[5][5]={
{-0.0009 , 0.003799 , 0.00666 , 0.00374 , 0.00186 },
{-0.0008 , 0.0176 , 0.0619 , 0.0159 , 0.00324 },
{0.00099 , 0.0475 , 0.666 , 0.0376 , 0.00758 },
{0.00242 , 0.02189 , 0.0624 , 0.0192 , 0.0008 },
{0.00182 , 0.00404 , 0.00479 , 0.00924 , 0.00189 }};
boost::multi_array_ref mg((double*)g,boost::extensts[5][5]);
我不喜欢这个,因为它需要2个变量而不是1个,三重冗余的[5][5]
标注(大小可以通过嵌套的花括号列表推断),以及从double[][]
到double*
的转换
我确实喜欢这样一个事实,即没有从g
复制到mg
,并且g
的初始化方式令人赏心悦目(即嵌套、结构化的初始值设定项列表,其中包含最少的多余字符)。有几个选项可用。所有这些都需要一些模板魔法;它们在句法表达能力和效率上有所不同。如果boost::multi_array
和friends确实提供了一些更有用的构造函数,生活会更轻松,但遗憾的是,在撰写本文时情况并非如此
1) 使用简单的初始值设定项\u列表
这一基本选项消除了一些冗余,并产生了相当好的语法糖。它使用一个helper函数,该函数接受一个初始值设定项\u列表
,将其转储到一个std::vector
,并使用该函数首先创建一个const\u multi\u array\u ref
,然后将其深度复制到一个多数组
#include <boost/multi_array.hpp>
#include <cassert>
#include <initializer_list>
#include <vector>
// Helper class to determine the full number of elements in the
// multi-dimensional array
template <std::size_t... vs> struct ArraySize;
template <std::size_t v, std::size_t... vs> struct ArraySize<v, vs...>
{ static constexpr std::size_t size = v * ArraySize<vs...>::size; };
template <> struct ArraySize<>
{ static constexpr std::size_t size = 1; };
// Creates your multi_array
template <typename T, int... dims>
boost::multi_array<T, sizeof...(dims)>
makeMultiArray(std::initializer_list<T> l)
{
constexpr std::size_t asize = ArraySize<dims...>::size;
assert(l.size() == asize); // could be a static assert in C++14
// Dump data into a vector (because it has the right kind of ctor)
const std::vector<T> a(l);
// This can be used in a multi_array_ref ctor.
boost::const_multi_array_ref<T, sizeof...(dims)> mar(
&a[0],
std::array<int, sizeof...(dims)>{dims...});
// Finally, deep-copy it into the structure we can return.
return boost::multi_array<T, sizeof...(dims)>(mar);
}
// Usage example
auto mg = makeMultiArray<double, 5, 5>({
-0.0009, 0.003799, 0.00666, 0.00374, 0.00186,
-0.0008, 0.0176, 0.0619, 0.0159, 0.00324,
0.00099, 0.0475, 0.666, 0.0376, 0.00758,
0.00242, 0.02189, 0.0624, 0.0192, 0.0008,
0.00182, 0.00404, 0.00479, 0.00924, 0.00189});
- Pro:保留初始值设定项的层次结构,以提高可读性;避免复制
- 缺点:仍然有一些你想摆脱的冗余
3) 使用嵌套的初始值设定项\u列表
这个似乎更合适,但效率较低。除了上面的代码之外,我们还需要一种方法来构造嵌套的初始值设定项列表
s,并将它们复制到数组中
// Nested initializer lists
template <typename T, std::size_t level> struct NestedInitializerList
{
typedef std::initializer_list<typename NestedInitializerList<T, level-1>::type> type;
};
template <typename T> struct NestedInitializerList<T, 1>
{
typedef std::initializer_list<T> type;
};
// Helpers which fill the array from a nested initializer_list
template <typename T>
void fillArray(const T& l, typename CArray<T>::type& a)
{
a = l;
}
template <typename T, int dim, int... dims>
void fillArray(typename NestedInitializerList<T, sizeof...(dims)+1>::type l,
typename CArray<T, dim, dims...>::type& a)
{
assert(l.size() == dim); // could be a static assert in C++14
int i=0;
for (auto it = l.begin(); it != l.end(); ++it, ++i)
{
fillArray<T, dims...>(*it, a[i]);
}
}
// Creates your multi_array
template <typename T, int... dims>
boost::multi_array<T, sizeof...(dims)>
makeMultiArray(typename NestedInitializerList<T, sizeof...(dims)>::type l)
{
typename CArray<T, dims...>::type a; // Multidimensional C array
fillArray<T, dims...>(l, a); // Fill from l
// Turn into multi_array_ref.
boost::const_multi_array_ref<T, sizeof...(dims)> mar(
reinterpret_cast<const double*>(a),
std::array<int, sizeof...(dims)>{dims...});
// Finally, deep-copy it into the structure we can return.
return boost::multi_array<T, sizeof...(dims)>(mar);
}
// Usage example
auto mg = makeMultiArray<double, 5, 5>(
{ { -0.0009, 0.003799, 0.00666, 0.00374, 0.00186 },
{ -0.0008, 0.0176, 0.0619, 0.0159, 0.00324 },
{ 0.00099, 0.0475, 0.666, 0.0376, 0.00758 },
{ 0.00242, 0.02189, 0.0624, 0.0192, 0.0008 },
{ 0.00182, 0.00404, 0.00479, 0.00924, 0.00189 } });
//嵌套的初始值设定项列表
模板结构嵌套初始化列表
{
typedef std::初始值设定项\列表类型;
};
模板结构嵌套初始化列表
{
typedef std::初始值设定项\列表类型;
};
//从嵌套初始值设定项列表填充数组的帮助程序
模板
无效填充数组(常量T&l,类型名称CArray::类型a)
{
a=l;
}
模板
void fillArray(类型名NestedinInitializerList::类型l,
typename CArray::type&a)
{
assert(l.size()==dim);//可以是C++14中的静态断言
int i=0;
对于(自动it=l.begin();it!=l.end();++it,++i)
{
填充数组(*it,a[i]);
}
}
//创建多维数组
模板
boost::多线程阵列
makeMultiArray(类型名称NestedinInitializerList::类型l)
{
typename CArray::type a;//多维C数组
fillArray(l,a);//从l填充
//变成多个数组。
boost::const\u multi\u array\u ref mar(
重新解释铸造(a),
std::数组{dims…});
//最后,将其深度复制到我们可以返回的结构中。
返回boost::多_阵列(mar);
}
//用法示例
自动mg=makeMultiArray(
{ { -0.0009, 0.003799, 0.00666, 0.00374, 0.00186 },
{ -0.0008, 0.0176, 0.0619, 0.0159, 0.00324 },
{ 0.00099, 0.0475, 0.666, 0.0376, 0.00758 },
{ 0.00242, 0.02189, 0.0624, 0.0192, 0.0008 },
{ 0.00182, 0.00404, 0.00479, 0.00924, 0.00189 } });
最后一个是一点灵感
- 赞成:用法完全是你想要的;无冗余,清晰的层次初始化结构
- 缺点:
fillArray()
例程是递归的,因此效率较低(我希望编译器也无法对其进行优化)
谢谢你的回答。不幸的是,它丢失了嵌套的初始值设定项列表。对于5x5列表来说,这并不是很糟糕,但是如果2D数组更大,那么在没有行标记的情况下很容易丢失。嗯,现在呢?我应该把它缩短一点。或者长度合适吗?这是一个严重的模板问题。谢谢你的例子。把它清理干净一点。
// Nested initializer lists
template <typename T, std::size_t level> struct NestedInitializerList
{
typedef std::initializer_list<typename NestedInitializerList<T, level-1>::type> type;
};
template <typename T> struct NestedInitializerList<T, 1>
{
typedef std::initializer_list<T> type;
};
// Helpers which fill the array from a nested initializer_list
template <typename T>
void fillArray(const T& l, typename CArray<T>::type& a)
{
a = l;
}
template <typename T, int dim, int... dims>
void fillArray(typename NestedInitializerList<T, sizeof...(dims)+1>::type l,
typename CArray<T, dim, dims...>::type& a)
{
assert(l.size() == dim); // could be a static assert in C++14
int i=0;
for (auto it = l.begin(); it != l.end(); ++it, ++i)
{
fillArray<T, dims...>(*it, a[i]);
}
}
// Creates your multi_array
template <typename T, int... dims>
boost::multi_array<T, sizeof...(dims)>
makeMultiArray(typename NestedInitializerList<T, sizeof...(dims)>::type l)
{
typename CArray<T, dims...>::type a; // Multidimensional C array
fillArray<T, dims...>(l, a); // Fill from l
// Turn into multi_array_ref.
boost::const_multi_array_ref<T, sizeof...(dims)> mar(
reinterpret_cast<const double*>(a),
std::array<int, sizeof...(dims)>{dims...});
// Finally, deep-copy it into the structure we can return.
return boost::multi_array<T, sizeof...(dims)>(mar);
}
// Usage example
auto mg = makeMultiArray<double, 5, 5>(
{ { -0.0009, 0.003799, 0.00666, 0.00374, 0.00186 },
{ -0.0008, 0.0176, 0.0619, 0.0159, 0.00324 },
{ 0.00099, 0.0475, 0.666, 0.0376, 0.00758 },
{ 0.00242, 0.02189, 0.0624, 0.0192, 0.0008 },
{ 0.00182, 0.00404, 0.00479, 0.00924, 0.00189 } });