0

I couldn't really find a solution online anywhere for this. I am a bit of a dinosaur from before C++11 and I couldn't figure out typecasting a constexpr.

Does anyone know how to convert a C-style array and/or a std::vector (integer) element into a constexpr?

That is to say, let's say

int a[]={1,2};
vector<int> v={1,2};

how would I convert a[1] and v[1] into constexpr?

constexpr int b=a[1];

for example, a compiler would complain in a for loop.

error: the value of ‘a’ is not usable in a constant expression
     constexpr int b=a[i];

I am pretty much out of ideas for the time being. Thanks

max66
  • 65,235
  • 10
  • 71
  • 111
Sj L
  • 41
  • 5
  • 2
    You can't. Only [constant expressions](https://en.cppreference.com/w/cpp/language/constant_expression) can be assigned to a `constexpr` variable. – NathanOliver Aug 19 '20 at 14:02
  • 2
    you'd need a timemachine to turn a value that is only known at runtime into one that is already known at compile-time – 463035818_is_not_an_ai Aug 19 '20 at 14:05
  • You can't , please look in cppreference (https://en.cppreference.com/w/cpp/language/constexpr ) "A constexpr variable must satisfy the following requirements: its type must be a LiteralType. it must be immediately initialized the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression " – AdabH Aug 19 '20 at 14:18
  • AdabH, I just did. Wow.. things have changed a lot since 2017... – Sj L Aug 19 '20 at 14:34
  • Can you please tell us what problem you are trying to solve by converting a dynamic value to constexpr? – Kit. Aug 19 '20 at 14:34
  • I am intending to use a switch case and create a a constexpr for each case similar to : https://stackoverflow.com/questions/16388510/evaluate-a-string-with-a-switch-in-c/16388594 except in my case, I want to use integers instead of strings for each case. – Sj L Aug 19 '20 at 14:39
  • I don't see anything similar there... no `constexpr` for sure. Why do you need `constexpr` for your switch? – Kit. Aug 19 '20 at 15:01
  • @Kit. I am referring to: constexpr unsigned int str2int(const char* str, int h = 0) { return !str[h] ? 5381 : (str2int(str, h+1) * 33) ^ str[h]; } switch (str2int(s)) { case str2int("Value1"): break; case str2int("Value2"): break; } – Sj L Aug 19 '20 at 16:08
  • [Works for me](https://godbolt.org/z/nq1aar). What's your problem, again? – Kit. Aug 19 '20 at 16:47
  • @Kit. ,I was able to modify it such that constexpr unsigned int str2int(const char* str, int h = 0) { return !str[h] ? 5381 : (str2int(str, h+1) * 33) ^ str[h]; } can take an array or vector of strings and used the str2int to set the case. This worked, but not when I switched integers. – Sj L Aug 19 '20 at 17:11
  • [Still works](https://godbolt.org/z/bEbjYK). Can you update your question with the example of code that works and the example of code that doesn't? Otherwise it's completely unknown what you are trying to achieve, as I hope you already understand that you cannot use case labels with values that aren't known to the compiler at compile time. – Kit. Aug 19 '20 at 17:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220106/discussion-between-sj-l-and-kit). – Sj L Aug 19 '20 at 18:36

2 Answers2

3

Suggestion: if you can use at least C++14, instead of std::vector, if you can, use a std::array

Declaring it constexpr

#include <array>

int main () 
 {
   constexpr std::array<int, 2u> a {1, 2};

   constexpr auto b = a[1];
 }

std::array is a type compatible with constexpr and so it's operator[]() (const version), or also it's at() method (const version).

C++14 is required because in C++11 std::array::operator[]() const and std::array::at() const aren't constexpr methods so can't be used in a constant expression.

Unfortunately, std::vector require memory allocation so isn't compatible (before C++20) with constexpr.

For the C-style array case, you have only to declare it constexpr

int main () 
 {
// VVVVVVVVV   
   constexpr int a[] = {1,2};

   constexpr auto b = a[1];
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    @idclev463035818 - Why not? Done. – max66 Aug 19 '20 at 14:31
  • Okay, that looks quite promising. Is there a way to generalize to a[i], or does the index have to be well defined? – Sj L Aug 19 '20 at 14:32
  • @SjL - Obviously the index has to be a constant expression too; so `constexpr auto index = 0u; constexpr auto b = a[index];` works, `auto index = 0u; constexpr auto b = a[index];` doesn't. – max66 Aug 19 '20 at 14:51
  • I see, do you have a suggestion on how to approach this if I want iterate this in a for loop? – Sj L Aug 19 '20 at 14:53
  • 1
    @SjL - If you just know the use of variadic templates... I usually pass through an helper function that accept a `std::index_sequence` (that contain indexes as template values, so a sequence of constant expressions) and calling it using `std::make_index_sequence` (that generate the template sequence of indexes). – max66 Aug 19 '20 at 14:59
0

The constexpr must have a constant expression, i.e. they must be known at compile time. You can't perform an assignment to b with a, it's an error in this case.

In the given code snippet, the a isn't defined as constexpr, thus, it doesn't explicitly tells the compiler that the expression is a constant.

Rohan Bari
  • 7,482
  • 3
  • 14
  • 34
  • But `a` is "known at compile time", or rather we know what it holds, at compile time. Please explain to OP why this is not enough. – einpoklum Aug 19 '20 at 14:20