web-dev-qa-db-ja.com

コンパイル時にstd :: arrayをアルゴリズムで初期化する

考慮してください:

static constexpr unsigned num_points{ 7810 };
std::array< double, num_points > axis;

for (int i = 0; i < num_points; ++i)
{
    axis[i] = 180 + 0.1 * i;
}

axisはクラス全体の定数です。他のグローバル変数のように初期化することは避けたいです。コンパイル時に実行できますか?


これは全体として最後のクラスです。

// https://www.nist.gov/pml/atomic-spectroscopy-compendium-basic-ideas-notation-data-and-formulas/atomic-spectroscopy
// https://www.nist.gov/pml/atomic-spectra-database
struct Spectrum
{
    static constexpr unsigned _num_points{ 7810 };
    using Axis = std::array< double, _num_points >;

    static constexpr Axis _x{ [] ()            // wavelength, nm
        {
            Axis a {};
            for( unsigned i = 0; i < _num_points; ++i )
            {
                a[ i ] = 180 + 0.1 * i;
            }
            return a;
        } () };
    Axis _y {};                                // radiance, W·sr−1·m−2
};

コードと変数の混合は見苦しいですが、少なくとも公式は読者の目の前にあります。他の解決策では、クラス内で定義された定数と型を取得するために、多くの型付けが必要でした。

または、囲炉裏を変更した場合、実行時にラムダを返すだけです。

36
Vorac

完全を期すために、関数の定義を必要とせず、代わりにラムダを使用するバージョンを次に示します。 C++ 17は定数式でラムダを使用する機能を導入したため、配列constexprを宣言し、ラムダを使用してそれを初期化できます。

static constexpr auto axis = [] {
    std::array<double, num_points> a{};
    for (int i = 0; i < num_points; ++i) {
        a[i] = 180 + 0.1 * i;
    }
    return a;
}();

()最後の行で、ラムダをすぐに呼び出します。)

auto宣言のaxisが気に入らない場合、実際の型を読み取るのが難しくなりますが、ラムダ内でその型を繰り返したくない場合は、代わりに行う:

static constexpr std::array<double, num_points> axis = [] {
    auto a = decltype(axis){};
    for (int i = 0; i < num_points; ++i) {
        a[i] = 180 + 0.1 * i;
    }
    return a;
}();
35
Nikos C.

次に、完全なコンパイル可能なコードを示します。

#include <array>

template<int num_points>
static constexpr std::array<double, num_points> init_axis() {
    std::array<double, num_points> a{};
    for(int i = 0; i < num_points; ++i) 
    {
        a[i] = 180 + 0.1 * i;
    }
    return a;
};

struct Z {
    static constexpr int num_points = 10;
    static constexpr auto axis = init_axis<num_points>();
};
32
SergeyA

std::index_sequenceトリックもあります( Wandbox example ):

template <unsigned... i>
static constexpr auto init_axis(std::integer_sequence<unsigned, i...>) {
   return std::array{(180 + 0.1 * i)...};
};

static constexpr auto axis = init_axis(std::make_integer_sequence<unsigned, num_points>{});
14
metalfox