1

I would like to initialize a big static (and possibly constant) array with a predetermined sequence. In this particular case it would be a sinetable, containing a digitized sine-wave.

Now, I know you can initialize arrays with:

#define TABLE_SIZE 2000
static float table[TABLE_SIZE] = { 0 , 0.124 , 0.245 , ...  } 

and all I need to do is generate all the sine values and paste them inside, but in my opinion this is incredibly ugly.

Is there a preprocessor directive or a lambda function or something for this?

Failing that, just a solution to calculating all the values at the start of the program and assigning them to the static array?

EDIT:

Thanks to TemplateRex's answer from c++11: Create 0 to N constexpr array in c++ , I have a working solution:

#define TABLE_SIZE 2000    
template<class Function, std::size_t... Indices>
    constexpr auto make_array_helper(Function f, std::index_sequence<Indices...>) 
-> std::array<typename std::result_of<Function(std::size_t)>::type, sizeof...(Indices)> 
{
    return {{ f(Indices)... }};
}

template<int N, class Function>
constexpr auto make_array(Function f)
-> std::array<typename std::result_of<Function(std::size_t)>::type, N> 
{
    return make_array_helper(f, std::make_index_sequence<N>{});    
}

constexpr float fun(double x) { return (float)sin(((double)x / (double)TABLE_SIZE) * M_PI * 2.0); }

static constexpr auto sinetable = make_array<TABLE_SIZE>(fun);

Unfortunately I am having difficulties integrating this into a class. Getting error : sinetable::make_array is used before its definition, I'm guessing because static members are defined before static methods. Or maybe it has to do with constexpr being inline.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Sir Mate
  • 75
  • 1
  • 6
  • 5
    Can you use `constexpr` from C++11? – Rakete1111 Oct 08 '16 at 18:49
  • Check out my very old answer :) http://stackoverflow.com/questions/35389493/is-it-possible-to-evaluate-array-on-compilation-time/35390025#35390025. Pure ugliness! Just define 2000 macros and you are good. – xinaiz Oct 08 '16 at 18:57
  • You have 2x `return` in `fun` body :) I still consider this a hack, `float[N]` is not the same as `std::array` :( – xinaiz Oct 08 '16 at 20:26

2 Answers2

2

What you're looking for is C++11's constexpr but you'd need either recursion of templates.

c++11: Create 0 to N constexpr array in c++

http://fendrich.se/blog/2012/11/22/compile-time-loops-in-c-plus-plus-11-with-trampolines-and-exponential-recursion/

However, C++'s standard math functions are non constexpr so you wouldn't be able to use them anyways so you're probably better off just initializing it conventionally somewhere.

James Deng
  • 173
  • 10
  • 1
    You know floating point numbers can't be template `non-type` parameters right? – xinaiz Oct 08 '16 at 19:01
  • Hmm? What do you mean? I think the bigger issue here is that none of the std::math are non constexpr – James Deng Oct 08 '16 at 19:08
  • The first link's second answer had what i was looking for. Copy-pasting provided working results, but i will have to study this incromprehensible template-wizarding for days. Thanks! – Sir Mate Oct 08 '16 at 19:17
  • @SirMate You got working floating-point array initialization with sine values thanks to this link? :) – xinaiz Oct 08 '16 at 19:23
  • Yes, while i am having trouble integrating this into a class, the answer from TemplateRex from the first link works for my case with minimal modifications. – Sir Mate Oct 08 '16 at 19:41
0

If you can't manage to achieve the initialization with template techniques that I don't know about, here is alternative, uglier approach:

You just define 2001 macros:

#include <cmath>

#define TABLE_SIZE 2000

#define SINE0 0.0f                          
#define SINE1 SINE0 ,std::sin( 1.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE2 SINE1 ,std::sin( 2.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE3 SINE2 ,std::sin( 3.0f * M_PI / ( 2 * TABLE_SIZE) )
//...

//...
#define SINE1998 SINE1997 ,std::sin( 1998.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE1999 SINE1998 ,std::sin( 1999.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE2000 SINE1999 ,std::sin( 2000.0f * M_PI / ( 2 * TABLE_SIZE) )

#define ALL_2001_SINES SINE2000

And just use it this way:

#include <iostream>

#include "file_with_macros.hpp" // contains above macros and includes <cmath>

static float const table[TABLE_SIZE+1] = {ALL_2001_SINES}; // + 1 because of inclusion of 
                                                           // both borders 0.0f and M_PI/2

int main()
{
    for(int i=0; i<TABLE_SIZE+1; ++i)
        std::cout << table[i] << ", ";
}

Demo

If you want only 91 values (of every degree), then you can change TABLE_SIZE to 90, and remove macros SINE91 to SINE2000, and define macro ALL_91_SINES as SINE_90.

Community
  • 1
  • 1
xinaiz
  • 7,744
  • 6
  • 34
  • 78