1

Suppose that I want to declare a local static constant array, but I don't know its initializer values in compile time, and those have to be calculated first. For example, I have an array int p[100]. I write a loop to fill it with first 100 prime numbers. After those are calculated, I define a static const int primes[100] which has to be initialized by the values of p. How can I do this?

P.S. The question of "why I want to declare a local static const object?" may not have a satisfactory answer, but I think this is not the case here.

P.S.S. I mentioned the prime numbers just as an example. That is not the point.

P.S.S.S. Let's say p has 1000000 members. Then the solution suggested by user2079303 surely deserves more upvotes.

12
  • 1
    @EddeAlmeida - that's simply not true. Constants can be initialised at runtime, just not changed. Consider constants local to a function Commented May 10, 2016 at 8:13
  • Ok @Smeeheey. I deleted the stupid comment I made before. Commented May 10, 2016 at 8:16
  • I should have said, then, that constants are initialised when they are created and can't be changed after that moment. Thus, one can't just create a constant to give it a value later. Is this correct? Commented May 10, 2016 at 8:18
  • 1
    If you really need a static const array that isn't really const, I'd use a combination of memcpy and const_cast. Commented May 10, 2016 at 8:21
  • Could you provide more details? @KarstenKoop Commented May 10, 2016 at 8:39

4 Answers 4

2

It's possible to initialize a static const array at run time, but a bit tedious:

int* init = get_run_time_array();
static const int primes[100] {
        init[0], init[1], init[1], init[2], init[3], init[4], init[5], // ...
};
Sign up to request clarification or add additional context in comments.

Comments

1

To sidestep your question, it is actually perfectly feasible to have your primes calculated at compile time using template meta-programming. The below code shows a possible way to do this. The main function creates instantiates the PrimeGen type to generate a compile-time std::array of the 1st 100 primes. Apologies that the code is somewhat hard to read as there is a lot of template boiler-plate here. Basically most of the logic occurs in the first PrimeGen specialisation, which uses the Sieve of Eratosthenes to generate primes, using the following basic formula:

  1. Start with N=100 (required number yet to generate), Next = 2, an empty list of primes and an empty list of filters

  2. Check if Next is prime (that is, passes all existing filters). If so, add it to the list of primes, decrement N and add a new filter which will fail to pass any number divisible by Next.

  3. Recurse to next specialisation of PrimeGen with the above modified parameters as well as with Next incremented to Next+1
  4. Terminate when N=0

Obviously the compilation time of this program will be relatively long as the compiler computes the primes.

    #include <iostream>
    #include <array>

    template <size_t Mod>
    struct ModFilter
    {
        template<size_t N>
        static constexpr bool apply()
        {
            return N % Mod != 0;
        }
    };

    template <size_t N, typename ... Filters>
    struct CheckFilters;

    template <size_t N>
    struct CheckFilters<N>
    {
        static const bool pass = true;
    };

    template <size_t N, typename Filter, typename ... Filters>
    struct CheckFilters<N, Filter, Filters...>
    {
        static const bool pass = Filter::template apply<N>() && CheckFilters<N, Filters...>::pass;
    };

    template<typename ... Filters>
    struct FilterPack{};

    template<size_t ... Numbers>
    struct NumberList{};

    template <size_t N, bool doAppend, typename Numbers>
    struct ConditionalAppend
    {
        typedef Numbers Output;
    };

    template <size_t N, size_t ... Numbers>
    struct ConditionalAppend<N, true, NumberList<Numbers...>>
    {
        typedef NumberList<Numbers..., N> Output;
    };

    template <size_t N, bool doAppend, typename Filters>
    struct ConditionalAppendFilter
    {
        typedef Filters Output;
    };

    template <size_t N, typename ... Filters>
    struct ConditionalAppendFilter<N, true, FilterPack<Filters...>>
    {
        typedef FilterPack<Filters..., ModFilter<N>> Output;
    };

    template<size_t N, size_t Next, typename Numbers, typename Filters>
    struct PrimeGen;

    template<size_t N, size_t Next, size_t ... Numbers, typename ... Filters>
    struct PrimeGen<N, Next, NumberList<Numbers...>, FilterPack<Filters...>>
    {
        static constexpr std::array<size_t, N + sizeof...(Numbers)> numbers
            = PrimeGen<CheckFilters<Next, Filters...>::pass ? N-1 : N,
                        Next+1,
                        typename ConditionalAppend<Next, CheckFilters<Next, Filters...>::pass, NumberList<Numbers...>>::Output,
                        typename ConditionalAppendFilter<Next, CheckFilters<Next, Filters...>::pass, FilterPack<Filters...>>::Output>
              ::numbers;

        static const int size = N + sizeof...(Numbers);
    };

    template<size_t Next, size_t ... Numbers, typename ... Filters>
    struct PrimeGen<0, Next, NumberList<Numbers...>, FilterPack<Filters...>>
    {
        static constexpr std::array<size_t, sizeof...(Numbers)> numbers = {Numbers...};
        static const int size = sizeof...(Numbers);
    };

    template<size_t N, size_t Next, size_t ... Numbers, typename ... Filters>
    constexpr std::array<size_t,N + sizeof...(Numbers)> PrimeGen<N, Next, NumberList<Numbers...>, FilterPack<Filters...>>::numbers;

    template<size_t Next, size_t ... Numbers, typename ... Filters>
    constexpr std::array<size_t,sizeof...(Numbers)> PrimeGen<0,Next,NumberList<Numbers...>,FilterPack<Filters...>>::numbers;

    int main()
    {
        using MyGen = PrimeGen<100, 2, NumberList<>, FilterPack<> >;

        for(int i=0; i<MyGen::size; ++i)
            std::cout << MyGen::numbers[i] << std::endl;

        return 0;
    }

1 Comment

Although I stated the primeness as an example and that was not the point, but your solution seems somehow legit. +1
0

The most efficient solution will be:

static const int primes[100] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541 };

You can even do away with your whole p calculation now.

1 Comment

Nope. Why waste time with a calculation when the results are already known?
0

I just read this great answer to another question in SO and figured it out. There is no need to declare a local variable as static const. It seems that only static would suffice to keep the calculated values intact outside the scope.

6 Comments

Why? @LightnessRacesinOrbit
There isn't enough detail here to say, but from what little you've told us, this sounds like a misconception.
In a comment, I stated that: for example, let's say I calculate the values of p and then write someptr=&p[0] where someptr is a global int*. If I exit the local scope, the calculated values would be destroyed. But if I first assign them to a static constant array, and then write someptr=&primes[0] they will remain unchanged outside the local scope. I hoped this would clarify the reason for this question, and I really can't see a misconception. @LightnessRacesinOrbit
Hmm, okay. In this answer, you seemed to suggest that static grants immutability. It doesn't. I guess what I don't understand is what const has to do with anything.
I agree. The word const may arise some misconceptions. At a first glance, I wanted them to be constant in local scope and accessible outside the local scope. It seems we generally can't have both. @LightnessRacesinOrbit
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.