6

Is it possible to declare a const array (possibly constexpr) at one point, then define it at another place, one element at a time?

E.g.

extern constexpr int myArray[100];


myArray[0] = myConstexprFunction(0);
myArray[1] = myConstexprFunction(1);
// ...
myArray[100] = myConstexprFunction(100);

What I'm trying to do will need something like this. Maybe it's possible using things like: http://b.atch.se/posts/constexpr-counter/

But if this technique is going to be illegal in the next C++ standard (I hope not) I would like to use a safer one.

[EDIT] how about relaxing some requirements.. let's say that I want to do something like this:

constexpr int myConstExprFunction(int arg) { return arg + 100;}
// other code...
constexpr int a = myConstExprFunctionBegin(10);
constexpr int b = myConstExprFunction(20);
constexpr int c = myConstExprFunction(30);
constexpr int d = myConstExprFunctionEnd(40);

what I would like to have is that the myConstExprFunctionEnd is able to generate a final array with the values created by the previous functions. Everything at compile time of course.

[EDIT2] C++11 solutions very welcomed

user3770392
  • 453
  • 5
  • 12

5 Answers5

6

The requirement of constexpr of the recent C++ is very relaxed, so you could just write:

// requires C++17:
constexpr auto myArray = [] {
    std::array<int, 100> result {};
    for (size_t i = 0; i < 100; ++ i) {
        result[i] = i * i;
    }
    return result;
}();

Note I used std::array<int, 100> instead of int[100] because a function cannot return a C array.

The above code requires C++17 for two reasons:

  1. constexpr lambda
  2. The mutable operator[] is not constexpr before C++17

Issue 1 can be easily worked-around using a separate constexpr function. Issue 2 can only be solved by defining your own array wrapper.

// requires C++14:

template <typename T, size_t n>
struct ConstexprArray {
    T data[n];
    constexpr ConstexprArray() : data{} {}
    constexpr T& operator[](size_t i) { return data[i]; }
};

constexpr auto initialize_my_array() -> ConstexprArray<int, 100> {
    ConstexprArray<int, 100> result {};
    for (size_t i = 0; i < 100; ++ i) {
        result[i] = i * i;
    }
    return result;
}

constexpr auto myArray = initialize_my_array();
Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
4

constexpr declares that it is possible to evaluate the value of the function or variable at compile time.

So the only way you could use it with array is like:

constexpr int myArray[100]{1 , 2 , 3 ,.........};

statements like

myArray[0] = myConstexprFunction(0);

can only be evaluated during runtime. So its not possible.

Sumeet
  • 8,086
  • 3
  • 25
  • 45
  • I'm able to fill that array using template metaprogramming techniques, but it is equivalent to creating a { ... } – user3770392 Apr 04 '17 at 11:18
4

Looking at your edit, I'd just answer no, because the compiler cannot transform a group of variables into an array. It just don't work that way. There isn't any construct in C++ that can take a bunch of declaration, delete them and replace it with another declaration. A source code preprocessor or generator might be able to permit the syntax you seek.

If you're interested in a solution that doesn't require external tooling, you can create a constexpr function that returns an array:

constexpr auto makeMyArray() {
    std::array<int, 100> myArray{};

    myArray[0] = myConstExprFunction(10);
    myArray[1] = myConstExprFunction(20);
    // ...

    return myArray;
}

Then, initialize your array:

constexpr auto myArray = makeMyArray();
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
3

If you want to declare constexpr an array and initialize it's value using a constexpr function... the best I can think is wrap the array in a struct/array and initialize it via a delegate constructor.

The following is a full working C++14 example

#include <utility>
#include <iostream>

constexpr int myConstexprFunction (int i)
 { return i << 1; } // return 2*i

template <std::size_t S>
struct wrapArray
 {
   int const myWrappedArray[S];

   template <int ... Is>
   constexpr wrapArray (std::integer_sequence<int, Is...> const &)
      : myWrappedArray { myConstexprFunction(Is)... }
    { }

   constexpr wrapArray ()
      : wrapArray(std::make_integer_sequence<int, S>())
    { }
 };


int main ()
 {
   constexpr wrapArray<100>  wa100;

   for ( auto i : wa100.myWrappedArray )
      std::cout << i << ", ";

   std::cout << std::endl;
 }

If you need a C++11 code, you have to implement a substitute for std::integer_sequence and for std::make_integer_sequence(). It's not difficult.

max66
  • 65,235
  • 10
  • 71
  • 111
  • yes this is similar to what I did, but is not enough for my purposes. I'll edit my question with some more detail – user3770392 Apr 04 '17 at 11:44
1

No.

constexpr variables must be "immediately initialised".

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055