使用C ++ 11或C ++ 14:
我有一个:
constexpr double [2][3][4] = some value;
我想要constexpr int [2][3][4]
。
(实际上我会想要constexpr my_type [2][3][4]
,但是一旦int工作,这应该是可以解决的。)
我想出的唯一解决方案是一个容器类,operator[]
被重载,所以它的行为就像一个数组。有没有办法保持标准数组语法?或者可能std::array<std::array...>>
而不创建新类?
我不希望输入为std::array
- 这是系统的约束。输入必须与C兼容。转换后的数组可以是C ++。
谢谢, 诺亚
答案 0 :(得分:2)
如果您接受constexpr std::array<std::array<int, 4U>, 3U>, 2U>
,那么......使用 SFINAE 标记调度,std::rank
,decltype()
,auto
作为返回类型和std::index_sequence
(所以C ++ 14解决方案)你可以使用getArray()
和他的助手getArrayH()
进行乒乓球比赛,如下所示
注意:回答修改(改进,恕我直言)从朱利叶斯的例子中获取灵感(谢谢!)
#include <array>
#include <iostream>
#include <type_traits>
template <typename T>
std::integral_constant<bool, std::rank<T>::value != 0U> isArray ();
template <typename targetT, typename origT, std::size_t Dim>
constexpr auto getArray (origT(&)[Dim]);
template <typename targetT, typename arrT, std::size_t ... Is>
constexpr auto getArrayH (arrT const & arr,
std::false_type const &,
std::index_sequence<Is...> const &)
{ return std::array<targetT, sizeof...(Is)>{ { targetT(arr[Is])... } }; }
template <typename targetT, typename arrT, std::size_t ... Is>
constexpr auto getArrayH (arrT const & arr,
std::true_type const &,
std::index_sequence<Is...> const &)
{ return std::array<decltype(getArray<targetT>(arr[0])), sizeof...(Is)>
{ { getArray<targetT>(arr[Is])... } }; }
template <typename targetT, typename origT, std::size_t Dim>
constexpr auto getArray (origT(&arr)[Dim])
{ return getArrayH<targetT>(arr, decltype(isArray<origT>()){},
std::make_index_sequence<Dim>{}); }
int main ()
{
constexpr double ad3[2][3][4]
{ { { 1.0, 2.0, 3.0, 4.0 },
{ 2.1, 3.1, 4.1, 5.1 },
{ 3.2, 4.2, 5.2, 6.2 } },
{ { 6.3, 5.3, 4.3, 3.3 },
{ 5.4, 4.4, 3.4, 2.4 },
{ 4.5, 3.5, 2.5, 1.5 } } };
for ( auto const & ad2 : ad3 )
for ( auto const & ad1 : ad2 )
for ( auto const & ad0 : ad1 )
std::cout << ad0 << ' ';
std::cout << std::endl;
constexpr auto ai3 = getArray<int>(ad3);
static_assert(std::is_same<decltype(ai3),
std::array<std::array<std::array<int, 4U>, 3U>, 2U> const>{}, "!");
for ( auto const & ai2 : ai3 )
for ( auto const & ai1 : ai2 )
for ( auto const & ai0 : ai1 )
std::cout << ai0 << ' ';
std::cout << std::endl;
}
答案 1 :(得分:1)
有一种方法可以通过逐步构建来实现此目的。也就是说,首先解决1D阵列的转换问题。然后基于该解决方案进行2D阵列的转换等。
template<typename U, typename T, std::size_t N, std::size_t... I>
constexpr
std::array<U, N>
convert1DArrayImpl(std::array<T, N> const &a, std::index_sequence<I...>) {
return {static_cast<U>(a[I])...};
}
template<typename U, typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr
std::array<U, N>
convert1DArray(const std::array<T, N>& a) {
return convert1DArrayImpl<U>(a, Indices{});
}
template<typename U, typename T, std::size_t N, std::size_t M, std::size_t... IN>
constexpr
std::array<std::array<U, N>, M>
convert2DArrayImpl(std::array<std::array<T, N>, M> a, std::index_sequence<IN...>) {
return {convert1DArray<U>(a[IN])...};
}
template<typename U, typename T, std::size_t N, std::size_t M, typename IndicesM = std::make_index_sequence<M>>
constexpr
std::array<std::array<U, N>, M>
convert2DArray(const std::array<std::array<T, N>, M>& a) {
return convert2DArrayImpl<U>(a, IndicesM{});
}
template<typename U, typename T, std::size_t N, std::size_t M, std::size_t K, std::size_t... IN>
constexpr
std::array<std::array<std::array<U, N>, M>, K>
convert3DArrayImpl(std::array<std::array<std::array<T, N>, M>, K> a, std::index_sequence<IN...>) {
return {convert2DArray<U>(a[IN])...};
}
template<typename U, typename T, std::size_t N, std::size_t M, std::size_t K, typename IndicesK = std::make_index_sequence<K>>
constexpr
std::array<std::array<std::array<U, N>, M>, K>
convert3DArray(const std::array<std::array<std::array<T, N>, M>, K>& a) {
return convert3DArrayImpl<U>(a, IndicesK{});
}
答案 2 :(得分:0)
不幸的是,std::array::operator[]
is not constexpr before C++17。因此,您可能需要提出自己的样板。
这是C ++ 17中的一个例子。如果你导出&#34; indices trick&#34;进入一个单独的函数(而不是lambda)并实现自己的std::array
版本,那么这种方法也适用于C ++ 14。
#include <array>
#include <iostream>
#include <utility>
////////////////////////////////////////////////////////////////////////////////
template<size_t... is, class F>
constexpr decltype(auto) indexer(std::index_sequence<is...>, F f) {
return f(std::integral_constant<std::size_t, is>{}...);
}
template<size_t N_, class F>
constexpr decltype(auto) indexer(F f) {
constexpr size_t max_index_length = 4096;
constexpr size_t N = std::min(N_, max_index_length);
static_assert(N == N_, "");
return indexer(std::make_index_sequence<N>{}, f);
}
////////////////////////////////////////////////////////////////////////////////
template<class T>
constexpr auto make_array(T val) {
return val;
}
template<class NestedArrays, std::size_t N>
constexpr auto make_array(NestedArrays(&arr)[N]) {
using NestedStdArrays = decltype(make_array(arr[0]));
return indexer<N>([=] (auto... ns) {
return std::array<NestedStdArrays, N>{
make_array(arr[ns])...
};
});
}
////////////////////////////////////////////////////////////////////////////////
int main() {
constexpr int input_from_c[1][3][2]{
{ {0, 10}, {20, 30}, {40, 50} }
};
constexpr auto nested_std_arrays = make_array(input_from_c);
using NestedStdArrays = std::decay_t<decltype(nested_std_arrays)>;
static_assert(
std::is_same<
NestedStdArrays,
std::array<std::array<std::array<int, 2>, 3>, 1>
>{}, ""
);
static_assert(0 == nested_std_arrays[0][0][0], "");
static_assert(10 == nested_std_arrays[0][0][1], "");
static_assert(20 == nested_std_arrays[0][1][0], "");
static_assert(30 == nested_std_arrays[0][1][1], "");
static_assert(40 == nested_std_arrays[0][2][0], "");
static_assert(50 == nested_std_arrays[0][2][1], "");
return 0;
}