简化冗余std :: array初始化,当时没有constexpr构造函数

Simplify redundant std::array initialization when class has no constexpr constructor

本文关键字:当时 构造函数 constexpr 初始化 冗余 std array      更新时间:2023-10-16

我有以下代码的复杂版本:

#include <array>
#include <cmath>
using namespace std;
class Dummy
{
    public:
        Dummy(const double a, const double f)
        {
            //Some complex calculations
        }
};
constexpr double values[] { 0.1, 0.2, 0.3, 0.4 };
constexpr auto N = sizeof(values) / sizeof(values[0]);
static const array<Dummy, N> dummies {Dummy(10 * values[0], M_PI * 0),
                                      Dummy(10 * values[1], M_PI * 1),
                                      Dummy(10 * values[2], M_PI * 2),
                                      Dummy(10 * values[3], M_PI * 3)};
int main()
{
    //Complex use of dummies
    return 0;
}

我想简化dummies数组的初始化,因为它是高度冗余的。但是,我一定是C 11,我无法将Dummy类更改为具有constexpr构造函数(这将极大地简化我的情况(。

我已经看过variadic模板,但似乎无法解决Dummy的构造函数不是constexpr

template<size_t... Is>
struct _Helper
{
    static constexpr array<Dummy, N> dummies {Dummy(10 * values[Is], M_PI * Is)...}; //Fails to compile because Dummy's constructor is not constexpr
};
static const array<Dummy, N> dummies { _Helper<0, 1, 2, 3>::dummies };

还有其他方法可以简化数组的初始化吗?可以将values重新列出为实际上可以在运行时转换回double[]的其他任何内容。

也许您可以如下创建一个make函数

template <std::size_t ... Is>
std::array<Dummy, sizeof...(Is)> makeDummArr (double const * vals)
 { return { { Dummy(10 * vals[Is], M_PI * Is)... } }; } }

并使用它来初始化

static const std::array<Dummy, N> dummies = makeDummArr<0, 1, 2, 3>(values);

可惜您一定会遇到C 11:如果您的Is...列表是顺序的(从零开始(,如果您可以使用C 14 ... SO std::make_index_sequencestd::index_sequence ...

我的意思是

template <std::size_t ... Is>
std::array<Dummy, sizeof...(Is)> makeDummArr
   (double const * vals, std::index_sequence<Is...> const &)
 { return { { Dummy(10 * vals[Is], M_PI * Is)... } }; }

static const std::array<Dummy, N> dummies
   = makeDummArr(values, std::make_index_sequence<4U>{});

(或者您可以遵循HolyBlackCat的建议,并在C 11中创建std::index_sequencestd::make_index_sequence的替代品(

以下代码与 @max66的建议相似,
但不需要您手动键入0, 1, ..., N-1

template <int ...I> struct int_seq // A rip-off of C++14 std::index_sequence.
{
    template <int X> using push_back = int_seq<I..., X>;
};
template <int N> struct make_int_seq_impl
{
    using type = typename make_int_seq_impl<N-1>::type::template push_back<N-1>;
};
template <> struct make_int_seq_impl<0>
{
    using type = int_seq<>;
};
template <int N> using make_int_seq = typename make_int_seq_impl<N>::type;
template <int ...I> array<Dummy, N> make_dummies(int_seq<I...>)
{
    return {Dummy(10 * values[I], M_PI * I)...};
}
static const array<Dummy, N> dummies = make_dummies(make_int_seq<N>{});