I've tried the other day with 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;
}
and, of course, it produced an error:
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,
^
I think this is not so much a problem with std::copy()
, as with std::begin()
and std::end()
that would handle multidimensional arrays. Is this an omission with the current C++ standard and how to work around it?
EDIT: I am convinced, the standard could fix this problem:
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]);
}
}
It won't work with a simple copy
call as plain arrays cannot be copied or assigned. However, you can copy the underlying elements and treat the multidimensional array as a one-dimensional one.
One convenient possibility is to use a flattened range accessors:
// 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))
Then,
std::copy( decayed_begin(a), decayed_end(a), decayed_begin(b) );
Demo.
Arrays have no assignment operator. So you need to copy the whole array element by element of type int.
For example you can write
std::copy( reinterpret_cast<int *>( a ),
reinterpret_cast<int *>( a ) + 10 * 20 * 30,
reinterpret_cast<int *>( b ) );
Or you can use std::for_each
or std::transform
with some compound lambda expressions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With