【问题标题】:Simplify redundant std::array initialization when class has no constexpr constructor当类没有 constexpr 构造函数时简化冗余 std::array 初始化
【发布时间】:2018-07-21 08:05:12
【问题描述】:

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

#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 构造函数(这将大大简化我的情况)。

我查看了可变参数模板,但似乎无法解决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[] 的东西。

【问题讨论】:

  • Dummy 有默认构造函数吗?
  • @Nelfeal:不,不幸的是,它没有。
  • 真实代码中你也有4个假人吗?
  • @HolyBlackCat:我有几个这样的数组,其中一些有超过 4 个元素。

标签: c++ arrays c++11 variadic-templates template-meta-programming


【解决方案1】:

也许你可以如下创建一个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... 那么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 的替代品)

【讨论】:

  • 我喜欢这个解决方案。我的目标是长期支持 C++14。为了确保正确的数组尺寸,我修改了您的 vals 参数,如下所示:const double (&amp;vals)[sizeof...(Is)]
  • @AndreasUnterweger - 工作,并提高了尺寸检查和安全性,但灵活性不够(你不能用指向 double 的指针初始化 dummies,而只能使用 C 风格的 double大批)。看看你的项目中哪个更好。
【解决方案2】:

下面的代码类似于@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>{});

【讨论】:

    猜你喜欢
    • 2016-02-16
    • 1970-01-01
    • 2022-01-22
    • 2021-04-18
    • 2014-02-27
    • 2015-09-04
    • 1970-01-01
    • 2016-12-29
    • 2016-11-06
    相关资源
    最近更新 更多