Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在编译或初始化时对长数组进行编程初始化_C++_C++11_Initialization - Fatal编程技术网

C++ 在编译或初始化时对长数组进行编程初始化

C++ 在编译或初始化时对长数组进行编程初始化,c++,c++11,initialization,C++,C++11,Initialization,下面是一段代码片段,说明了我的问题: const float D = 0.1F; const float A[4] = {sin(0*D), sin(1*D), sin(2*D), sin(3*D)}; 假设全局数组A长得多,您不想重复输入所有这些内容。是否有一种在编译或初始化时初始化数组的较短方法,即不必编写初始化函数并在程序中调用它?您可以使用代码生成器生成初始化代码。也就是说,编写将为您编写初始化代码的程序。实际上,您可以在生成时计算值 请记住C++允许在最后一个元素之后放置,。也

下面是一段代码片段,说明了我的问题:

const float D    = 0.1F;
const float A[4] = {sin(0*D), sin(1*D), sin(2*D), sin(3*D)};

假设全局数组
A
长得多,您不想重复输入所有这些内容。是否有一种在编译或初始化时初始化数组的较短方法,即不必编写初始化函数并在程序中调用它?

您可以使用代码生成器生成初始化代码。也就是说,编写将为您编写初始化代码的程序。实际上,您可以在生成时计算值

<>请记住C++允许在最后一个元素之后放置<代码>,<代码>。也没有必要指定数组大小。这两件事应该可以简化生成器的编写

这段简单的python代码应该可以很好地工作:

from math import sin

print('const float A[', N, '] = {')
for i in range(N):
    print('\t', sin(i*D), ',', sep='')
print('};')

您可以在动态初始化期间初始化,如下所示:

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);
const float*init_a(float x_)
{
静态浮点数据[4];
对于(unsigned i=0;i您可以使用,尤其是
BOOST\u PP\u 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;
}
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

但是请注意,为了在编译时生成,数组生成器中的输入函数必须是
constepr
。三角函数不是这种情况(即它们不是
constepr
)因此,
array
s
A
B
的初始化将在初始化时进行,而
array C
的生成将在编译时进行。

好的,我刚刚意识到这实际上并没有回答问题,因为它指定了“无需编写初始化函数并在程序中调用它?”但我想不出一个方便的替代方法

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);
模板
std::数组GetLookupTable(浮点d)
{
std::数组表;
//…在此处填充表格
返回表;
}
//全球某地
(静态?)const auto Table_10x5=GetLookupTable(5.0f);
假设全局数组A长得多,并且您不想重复执行所有这些键入操作。是否有一种更短的方法在编译或初始化时初始化数组A

创建一个生成器并将其传递给
std::generate_n()
(或普通
std::generate()

#包括
#包括
#包括
模板
结构单发电机{
单发电机(标准::大小\u t开始=0,值\u t计数器\u标量=1)
:索引{start},
标量{counter_scalar}{
}
值运算符()(){
返回sin(索引+++*标量);
}
标准:尺寸指数;
标量值;
};
模板
std::数组初始表(const std::size\u t start,
常量值(计数器(标量){
std::阵列arr;
单发电机发电机(启动、计数器);
std::generate(arr.begin(),arr.end(),gen);
返回arr;
}
常数自动保持(初始表(0,0.1f));

第一部分在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;
如果你有一个
constepr
sin
函数,你甚至可以把
poly\u sin
做成一个
constepr
函数,基本上保证在编译时对它进行评估

如果是这种情况,则使
D
constexpr
与两个
poly\u sin
函数相同

如前所述,这发生在动态初始化时

虽然数组似乎被复制了两次,但RVO省略意味着任何一个好的编译器都会直接在
A
中构造它

如果您想在一般情况下做到这一点,请首先从上述
索引开始。然后添加以下内容:

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)); } );
templateusing result\u of\u t=typename std::result\u of::type;
命名空间详细信息{
模板
std::数组,N>
生成数组(F&&F,索引){
返回{f(Is)…};
}
}
模板
std::数组,N>
生成数组(F&&F){
返回细节::make_数组(std::forward(f),make_索引{});
}
const auto A=make_数组([](无符号i){return float(i*sin(D));});

它使用lambda来传递重复构建数组的代码。遗憾的是,lambda在默认情况下不是
constexpr
,因此您无法在编译时执行此操作。

如果
a
数组始终保持不变并且非常大,您可以编写一个短脚本,用于计算数组中的每个值并输出可以在源代码中使用以进行静态初始化


如果公式很简单,甚至MS Excel也可以用来生成这种静态初始化数据。

您显示的初始化不是在静态初始化时发生的,而是在动态初始化时发生的,也就是说,在运行时。
sin
不是
constexpr
。代码段看起来并不是真正的illustr回答你的问题。@IgorTandetnik你说得对,我将编辑我的问题。这是用于查找表吗?简单地执行计算可能比在现代CPU上查找值更快。@NeilKirk这是一个查找表,但计算三角函数仍然比从现代CPU上的小查找表中获取三角函数慢得多。你是怎么做的知道吗,你在真实的应用程序中测量了吗?一个简单的基准不能使用,因为它不会对真实程序的缓存使用进行建模。查找表使用缓存空间。谢谢,它满足了我的要求,并且比基于模板的解决方案更易于阅读。我只是希望有一些东西看起来更像C++17和更高版本,而不是普通的旧C…I oFTEN指定数组长度,所以当重读代码时,我不必计数,只要长一点,长度就不明显了。如果我只能在C++代码中使用Python或类似的语言来进行元编程……最好是每次生成生成器源代码时都自动配置生成脚本来生成源代码。挂起。这样生成将自动进行,几乎不会造成时间开销。生成器很容易打印arr
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>{} );
}
const float D    = 0.1F;
const auto A = poly_sin<4>(D);
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)); } );