c++ initialization c++17 compile-time stdarray

c++ - Inicialice un std::array algorítmicamente en tiempo de compilación



initialization c++17 (3)

Aquí está el código compilable completo:

#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>(); };

Considerar:

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 es una constante de toda la clase. Quiero evitar inicializarlo como cualquier otra variable global. ¿Se puede hacer en tiempo de compilación?

Esta es la clase final en su totalidad:

// 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 };

La mezcla de código y variables es desagradable, pero al menos la fórmula está justo en frente de los ojos del lector. Cualquier otra solución involucró mucho escribir para obtener la constante y el tipo definidos en la clase.

O si cambio mi hogar, simplemente puedo devolver el lambda en tiempo de ejecución.


Para completar, aquí hay una versión que no requiere la definición de una función, sino que utiliza una lambda. C ++ 17 introdujo la capacidad de usar lambdas en expresiones constantes, por lo que puede declarar su matriz constexpr y usar una lambda para inicializarla:

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; }();

(Note el () en la última línea, que llama a la lambda de inmediato).

Si no te gusta el auto en la declaración del axis porque hace que sea más difícil leer el tipo real, pero no quieres repetir el tipo dentro de la lambda, puedes hacer lo siguiente:

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; }();


También está el truco std::index_sequence ( ejemplo de Wandbox ):

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>{});