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

3
  • Have you already tried this? What errors did you get? Commented Apr 4, 2017 at 11:09
  • @RichardCritten yes, sure I've tried, but I get different kind of errors ( .. has been previously declared.. / conflicting declaration ... etc.). The only way I could do something like that has been in a recursive way using template metaprogramming Commented Apr 4, 2017 at 11:16
  • In English, sentences begin with capital letters. Commented Apr 4, 2017 at 11:18

5 Answers 5

7

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();
Sign up to request clarification or add additional context in comments.

5 Comments

still not exactly what I was looking for but very interesting! have you read the second part of the post (the edit) ?
@user3770392 How is the second part not capable with C++17?
I was meaning the second part of my post. By the way, I can use just C++11. C++14 elements like indices etc ok, I can simulate them
@user3770392 OK I see (yes I do mean the second part of your post).
ahahaa ok, let's say I meant just C++11 then :)
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();

11 Comments

Not in C++11. You can however, replace loops or multiple statements with recursive function call. It requires C++14. You cannot have multiple statements in a constexpr function in C++11.
I think I can use the comma operator too :)
Oh maybe! Didn't thought about that! But I doubt you can mutate values with this.
Try -std=c++14
eheheh I know how to use that directive, but I can't use it right now...
|
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.

1 Comment

I'm able to fill that array using template metaprogramming techniques, but it is equivalent to creating a { ... }
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.

1 Comment

yes this is similar to what I did, but is not enough for my purposes. I'll edit my question with some more detail
1

No.

constexpr variables must be "immediately initialised".

Comments

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.