std::copy用于多维数组
std::copy for multidimensional arrays
我前几天用gcc-4.9.1
试过:
int main()
{
int a[10][20][30];
int b[10][20][30];
::std::copy(::std::begin(a), ::std::end(a), ::std::begin(b));
return 0;
}
当然,它产生了一个错误:
In file included from /usr/include/c++/4.9.2/bits/char_traits.h:39:0,
from /usr/include/c++/4.9.2/ios:40,
from /usr/include/c++/4.9.2/ostream:38,
from /usr/include/c++/4.9.2/iostream:39,
from t.cpp:1:
/usr/include/c++/4.9.2/bits/stl_algobase.h: In instantiation of 'static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = int [20][30]; bool _IsMove = false]':
/usr/include/c++/4.9.2/bits/stl_algobase.h:396:70: required from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = int (*)[20][30]; _OI = int (*)[20][30]]'
/usr/include/c++/4.9.2/bits/stl_algobase.h:434:38: required from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = int (*)[20][30]; _OI = int (*)[20][30]]'
/usr/include/c++/4.9.2/bits/stl_algobase.h:466:17: required from '_OI std::copy(_II, _II, _OI) [with _II = int (*)[20][30]; _OI = int (*)[20][30]]'
t.cpp:10:62: required from here
/usr/include/c++/4.9.2/bits/stl_algobase.h:373:4: error: static assertion failed: type is not assignable
static_assert( is_copy_assignable<_Tp>::value,
^
我认为这不是std::copy()
的问题,而是处理多维数组的std::begin()
和std::end()
的问题。这是当前C++标准的遗漏以及如何解决它?
编辑:我相信,该标准可以解决此问题:
namespace std
{
template <typename T, size_t M, size_t N>
constexpr typename remove_all_extents<T>::type*
begin(T (&array)[M][N])
{
return begin(array[0]);
}
template <typename T, size_t M, size_t N>
constexpr typename remove_all_extents<T>::type*
end(T (&array)[M][N])
{
return end(array[M - 1]);
}
}
它不适用于简单的copy
调用,因为无法复制或分配纯数组。但是,您可以复制基础元素并将多维数组视为一维数组。
一种方便的可能性是使用扁平化的范围访问器:
// For convenient trailing-return-types in C++11:
#define AUTO_RETURN(...)
noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) {return (__VA_ARGS__);}
template <typename T>
constexpr auto decayed_begin(T&& c)
AUTO_RETURN(std::begin(std::forward<T>(c)))
template <typename T>
constexpr auto decayed_end(T&& c)
AUTO_RETURN(std::end(std::forward<T>(c)))
template <typename T, std::size_t N>
constexpr auto decayed_begin(T(&c)[N])
AUTO_RETURN(reinterpret_cast<typename std::remove_all_extents<T>::type*>(c ))
template <typename T, std::size_t N>
constexpr auto decayed_end(T(&c)[N])
AUTO_RETURN(reinterpret_cast<typename std::remove_all_extents<T>::type*>(c + N))
然后
std::copy( decayed_begin(a), decayed_end(a), decayed_begin(b) );
演示。
数组没有赋值运算符。因此,您需要按 int 类型的元素复制整个数组元素。
例如,你可以写
std::copy( reinterpret_cast<int *>( a ),
reinterpret_cast<int *>( a ) + 10 * 20 * 30,
reinterpret_cast<int *>( b ) );
或者,您可以将 std::for_each
或 std::transform
与一些复合 lambda 表达式一起使用。
这是另一个模板变体,它适用于任何多尺寸数组,无论维数如何。 它利用多维元素是连续的和强制转换的事实来处理数组,就好像它是一个平面的一维数组一样:
template <typename T>
typename std::remove_all_extents<T>::type* mbegin(T& arr) {
return reinterpret_cast<typename std::remove_all_extents<T>::type*>(&arr);
}
template <typename T>
size_t msize(const T& a)
{
return sizeof(T) / sizeof(typename std::remove_all_extents<T>::type);
}
template <typename T>
typename std::remove_all_extents<T>::type* mend(T& arr) {
return reinterpret_cast<typename std::remove_all_extents<T>::type*>(&arr)+msize(arr);
}
你称之为:
::std::copy(mbegin(a), mend(a), mbegin(b));
这里的诀窍是使用类型 T 作为多维数组 (int[][]..[]
),并使用 typename std::remove_all_extents<T>::type
删除维度并得到基类型 (int
)。
这个答案已经找到了一些非常有趣的答案。 大多数是基于这样一个事实,即C++标准确保多维数组的元素是连续的,从而可以(通过强制转换)像处理一维数组一样处理数组。
为了完整起见,我提出这个变体。 它使用模板和自动扣除数组大小:
template <typename T, size_t N1, size_t N2, size_t N3>
T* begin(T(&arr)[N1][N2][N3]) {
return reinterpret_cast<T*>(arr);
}
template <typename T, size_t N1, size_t N2, size_t N3>
T* end (T(&arr)[N1][N2][N3]) {
return reinterpret_cast<T*>(arr)+N1*N2*N3;
然后,您可以继续复制:
::std::copy(begin(a), end(a), begin(b));
另一种方法是使用相同的模板方法定义 3D 迭代器。
在阅读了所有答案之后,这是我的 5 美分,似乎有效:
template <typename T>
constexpr T* begin(T& value) noexcept
{
return &value;
}
template <typename T, ::std::size_t N>
constexpr typename ::std::remove_all_extents<T>::type*
begin(T (&array)[N]) noexcept
{
return begin(array[0]);
}
template <typename T>
constexpr T* end(T& value) noexcept
{
return &value + 1;
}
template <typename T, ::std::size_t N>
constexpr typename ::std::remove_all_extents<T>::type*
end(T (&array)[N]) noexcept
{
return end(array[N - 1]);
}
我不会接受我自己的答案,如果有什么问题,投反对票或评论,我会删除。
扁平版本的联合怎么样?
int main()
{
union
{
int a[10][20][30];
int fa[10 * 20 * 30];
};
union
{
int b[10][20][30];
int fb[10 * 20 * 30];
};
::std::copy(::std::begin(fa), ::std::end(fa), ::std::begin(fb));
return 0;
}
- 并行用于C++17中数组索引范围内的循环
- 运算符重载 (+),用于添加两个具有 C++ 的数组
- 这种用于查找连续子数组中最大和的递归算法有什么优势吗?
- 为什么数组大小信息可用于"sizeof"运算符和 delete[] 运算符,但在将数组作为参数传递到
- 迭代器库中的 std::size() 不适用于传递给函数的 C 样式数组
- 自定义 STL 兼容迭代器,用于迭代 2D 数组类的列
- 用于查找数组中最大元素的出现次数的代码,给出分段错误
- 用于 progmem 的C++和头文件压缩的 Web 文件字节数组
- C++ 函数,用于查找数组中四个最小最大元素的总和不起作用
- C++ 用于在数组中打印字符串的随机数
- 如何使函数返回数组?用于制作在VB.NET中使用的DLL
- std::array与C样式数组用于连续内存
- 如何使用 WIN RPC 发送终止的字符数组(用于将图像从客户端上传到服务器)
- TensorFlow C :将数组用于feed_dict
- 将一个函数中声明的数组用于另一个函数
- 链表与动态数组用于使用向量类实现堆栈
- 将数组用于函数输入参数
- 矢量与数组用于大量元素
- 多维数组 - 用于在C++中存储非常大的 2D 数据的数据结构
- 有没有更好的方法可以通过模板用预先计算的值填充数组(用于运行时)