以下是说明我的问题的代码段:
const float D = 0.1F;
const float A[4] = {sin(0*D), sin(1*D), sin(2*D), sin(3*D)};
想象一下,全局数组A
要长得多,而且你不想做所有这些重复输入。在编译或初始化时是否有更短的方法来初始化数组A,即无需编写初始化函数并在程序中的某处调用它?
答案 0 :(得分:6)
您可以在动态初始化时间内初始化A,如下所示:
const float *init_a(float x_)
{
static float data[4];
for(unsigned i=0; i<4; ++i)
data[i]=sin(i*x_);
return data;
}
const float D=0.1f;
const float *A=init_a(D);
答案 1 :(得分:5)
您可以使用代码生成器生成初始化代码。也就是说,编写将为您编写初始化代码的程序。实际上,您可以在生成时计算值。
请记住,C ++允许在最后一个元素之后放置,
。也没有必要指定数组大小。这两件事应该可以轻松编写发电机。
这个简单的python代码应该运行良好:
from math import sin
print('const float A[', N, '] = {')
for i in range(N):
print('\t', sin(i*D), ',', sep='')
print('};')
答案 2 :(得分:4)
第一部分在C ++ 14中已经过时,但不长:
template<unsigned...>struct indexes { using type=indexes; };
template<unsigned Max, unsigned...Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;
这是一些模板元编程,它允许我们创建并传递索引包。
然后生成数组的一些代码:
namespace details {
template<std::size_t N, unsigned...Is>
std::array<float, N> poly_sin(float src, indexes<Is...>) {
return { (Is*sin(src))... };
}
}
template<std::size_t N>
std::array<float, N> poly_sin(float src) {
return details::poly_sin<N>( src, make_indexes_t<N>{} );
}
第一种方法需要indexes<Is...>
,我们计划Is...
为0, 1, 2, ..., N-1
。然后,它将参数包扩展为正确大小的std::array
。
make_indexes_t<N>{}
将(在编译时)扩展为indexes<0, 1, 2, ..., N-1>{}
,然后传递给details::poly_sin
,然后Is...
可以推导const float D = 0.1F;
const auto A = poly_sin<4>(D);
并在其中使用它们。
和使用点:
constexpr
如果您有sin
poly_sin
函数,您甚至可以使constexpr
成为D
函数,并且基本保证在编译时对其进行评估。
如果是这种情况,请使用constexpr
poly_sin
和两个A
功能相同。
如上所述,这发生在动态初始化时。
虽然看起来数组被复制了两次,但RVO elision意味着任何体面的编译器都会在indexes
中直接构造它。
如果您希望能够执行此操作,请先从上面的template<class Sig>using result_of_t=typename std::result_of<Sig>::type;
namespace details {
template<std::size_t N, class F, unsigned... Is>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f, indexes<Is...> ) {
return { f( Is )... };
}
}
template<std::size_t N, class F>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f ) {
return details::make_array( std::forward<F>(f), make_indexes_t<N>{} );
}
const auto A = make_array<4>( [](unsigned i){ return float(i*sin(D)); } );
代码开始。然后添加:
constexpr
使用lambda传递重复的代码来构建数组。遗憾的是,lambdas默认情况下不是{{1}}所以你不能在编译时这样做。
答案 3 :(得分:3)
您可以使用boost.preprocessor,尤其是BOOST_PP_ENUM
宏,如下例所示:
#include <iostream>
#include <cmath>
#include <boost/preprocessor/repetition/enum.hpp>
#define SIZE 4
#define D 0.1
#define ORDER(z, n, text) std::sin(n * D)
double const A[SIZE] = { BOOST_PP_ENUM(SIZE, ORDER, ~) };
int main() {
for(auto i : A) std::cout << i << std::endl;
}
或者,您可以使用std::array
而不是原始数组,并通过使用模板元编程在编译时生成std::array
。如下例所示:
template<typename T, typename F, int SIZE, int... N>
constexpr std::array<T, SIZE>
genarray(F f) {
return std::array<T, SIZE>{{ f(N)... }};
}
template<typename T, typename F, int SIZE, int...> struct recursive_gen;
template<typename T, typename F, int SIZE, int... Args>
struct recursive_gen<T, F, SIZE, 0, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return genarray<T, F, SIZE, 0, Args...>(f);
}
};
template<typename T, typename F, int SIZE, int N, int... Args>
struct recursive_gen<T, F, SIZE, N, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, N - 1, N, Args...>::generate(f);
}
};
template<typename T, int SIZE>
struct array_generator {
template<typename F>
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, SIZE - 1>::generate(f);
}
};
std::array<double, 4> const A = array_generator<double, 4>::generate([](int i) { return std::sin(0.1 * i);});
std::array<double, 4> const B = array_generator<double, 4>::generate([](int i) { return std::cos(0.1 * i);});
constexpr int fun(int i) { return 2 * i; }
constexpr std::array<int, 4> const C = array_generator<int, 4>::generate(fun); // generation during compile time
但请注意,为了在编译时生成,array_generator
中的输入函数必须为constexpr
。对于三角函数不是这种情况(即,它们不是constexpr
)。因此,array
s A
和B
的初始化将在初始化时进行,而array C
的生成将在编译时进行。
答案 4 :(得分:3)
好的我刚刚意识到这实际上没有回答这个问题,因为它指定“无需编写初始化函数并在程序中的某个地方调用它?”但我想不出一个方便的选择。
template<size_t N>
std::array<float, N> GetLookupTable(float d)
{
std::array<float, N> table;
// .. populate table here
return table;
}
// a global somewhere
(static?) const auto Table_10x5 = GetLookupTable<10>(5.0f);
答案 5 :(得分:2)
想象一下,全局数组A要长得多,而且你不想做所有这些重复输入。是否有更短的方法在编译或初始化时初始化数组A
创建一个生成器并将其传递给std::generate_n()
(或普通std::generate()
)。
#include <algorithm>
#include <array>
#include <cmath>
template <typename Value_t>
struct SinGenerator{
SinGenerator(std::size_t start = 0, Value_t counter_scalar = 1)
: index{start},
scalar{counter_scalar} {
}
Value_t operator()() {
return sin(index++ * scalar);
}
std::size_t index;
Value_t scalar;
};
template <typename Value_t, std::size_t Size>
std::array<Value_t, Size> init_table(const std::size_t start,
const Value_t counter_scalar) {
std::array<Value_t, Size> arr;
SinGenerator<Value_t> gen(start, counter_scalar);
std::generate(arr.begin(), arr.end(), gen);
return arr;
}
const auto kSinTable(init_table<float, 10>(0, 0.1f));
答案 6 :(得分:2)
如果你A
数组总是保持不变并且非常大,你总是可以编写一个简短的脚本来计算数组中的每个值,并且可以在源代码中使用输出来进行静态初始化。 / p>
如果公式很简单,甚至可以使用MS Excel 生成那种静态初始化数据。