use c++ 11 constexpr for std::map initialization

c language basics
in c
how to print in c
in c
c programming definition
logical operators in c
why do we use c programming
conditional operator in c

I want to initialize a std::map with the keys being a constexpr. Consider the following C++11 MWE:

#include <map>
using std::map;

constexpr unsigned int str2int(const char* str, const int h = 0) {
    return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
}

const map<unsigned int, const char*> values = {
    {str2int("foo"), "bar"},
    {str2int("hello"), "world"}
};

int main() { return 0; }

While the code compiles which recent clang and gcc, the resulting binary will contain the strings of the key type:

Why are the keys contained in the binary even though they are used as constexpr's? Any way to work around this behavior?

Of course the map initialization will occur at runtime. But shouldn't the values in the binary be replaced with the constexpr's at compiletime?

Note: This is of course a simplified example. I know there are different boost structures which may be more suitable for this use case. I'm especially interested in why this is happening.

[Edit]

The behavior occurs no matter if optimizations are enabled or not. The following code compiles with bar being the only user defined string in the string table:

#include <map>
#include <iostream>
#include <string>

using namespace std;

constexpr unsigned int str2int(const char* str, const int h = 0) {
  return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
}

int main() {
  string input;
  while(true) {
    cin >> input;
    switch(str2int(input.c_str())) {
      case str2int("quit"):
      return 0;
      case str2int("foo"):
      cout << "bar" << endl;
    }
  }
}

To verify the results I was using a small shell script

$ for x in "gcc-mp-7" "clang"; do 
  $x --version|head -n 1
  $x -lstdc++ -std=c++11 -Ofast constexpr.cpp -o a
  $x -lstdc++ -std=c++1z -Ofast constexpr.cpp -o b
  strings a|grep hello|wc -l
  strings b|grep hello|wc -l
done

gcc-mp-7 (MacPorts gcc7 7.2.0_0) 7.2.0
       1
       0
Apple LLVM version 8.1.0 (clang-802.0.38)
       1
       0

I cannot reproduce with neither g++ (trunk) or clang++ (trunk). I used the following flags: -std=c++1z -Ofast. I then checked the contents of the compiled binary with strings: neither "foo" or "hello" were there.

Have you compiled with optimizations enabled?

Regardless, your use of str2int does not force compile-time evaluation. In order to force it, you can do:

constexpr auto k0 = str2int("foo");
constexpr auto k1 = str2int("hello");

const map<unsigned int, const char*> values = {
    {k0, "bar"},
    {k1, "world"}
};

What are the benefits of learning C programming?, since it's very flexible and versatile, allowing maximum control with minimal commands. Javascript appears to be disabled Enable javascript and refresh the page to access online banking.

Cannot reproduce your issue using --std=c++11 -O2 in GCC 7.2, clang 5.0 or MSVC 17.

DEMO

Are you building with debug symbols on (-g)? That could be what you're seeing.

Advantages of C over C++, is default choice for source level programming, like kernel programming, driver development etc. Uses of C++ Applications: It is used for the development of new applications of C++. The applications based on the graphic user Games: This language is also used for developing games. It overrides the complexity of 3D games. It helps in optimizing Animation: There is animated software, which

Declaring only as const is not enough. The strings are included in the binary because:

const map<unsigned int, const char*> values

is const, but not constexpr. It will run 'str2int' when your program starts, not at compile time. Being const will only guarantee you that it will not allow further modifications, but makes no compile time compromises.

It seams you're searching for the Serge Sans Paille's Frozen constexpr containers -- https://github.com/serge-sans-paille/frozen

Although I don't know if it will work on C++11, if you want performance gains, it definitely worth it a try.

You can create maps that are hashed at compile time and will give you the additional benefit of producing a perfect hash function -- allowing all keys to be accessed in O(1) time (constant time).

It is a very competent substitute for gperf indeed.

Clang and GCC, currently, impose a limit on the number of keys you are able to process at compile time. Producing a map with 2048 keys turned out OK on my 1G RAM VPS only with clang. GCC is currently even worse and will eat all your RAM much sooner.

Why Code in C Anymore?, (so, any enterprise apps or client-facing software), the difference is not substantial. Announcement: Coronavirus COVID-19 Update: At USE Credit Union the health and safety of our members, staff and family is our utmost concern and we are closely monitoring coronavirus (COVID-19) to make sure we’re able to safely provide service to you. We will continue to follow instructions from local and national health authorities.

template<unsigned int x>
using kuint_t = std::integral_constant<unsigned int, x>;

const map<unsigned int, const char*> values = {
  {kuint_t<str2int("foo")>::value, "bar"},
  {kuint_t<str2int("hello")>::value, "world"}
};

that should force compile time evaluation.

In c++14 it is a bit less verbose:

template<unsigned int x>
using kuint_t = std::integral_constant<unsigned int, x>;
template<unsigned int x>
kuint_t<x> kuint{};

const map<unsigned int, const char*> values = {
  {kuint<str2int("foo")>, "bar"},
  {kuint<str2int("hello")>, "world"}
};

and in c++17:

template<auto x>
using k_t = std::integral_constant<std::decay_t<decltype(x)>, x>;
template<auto x>
k_t<x> k{};

const map<unsigned int, const char*> values = {
  {k<str2int("foo")>, "bar"},
  {k<str2int("hello")>, "world"}
};

it works with most primitive type constants without a type-specific version.

What does C stand for in the C language?, That means that you can use C to create lists of instructions for a computer to follow. C is one of thousands of programming languages currently in use. C has  At USE Federal Credit Union, no two members are the same. Blue or white collar, younger or wiser, they all have one thing in common - they hustle for every dollar they earn. We show our appreciation for that determination with low rates and consistent, personalized care.

What is C?, C compiles down to machine code and doesn't require any runtime support for the language itself. This means that it's possible to write code  However if you are compiling C code using your C++ compiler, you don’t want to have to tweak all these calls from printf() to std::printf(). Fortunately in this case the C code will use the old-style header <stdio.h> rather than the new-style header <cstdio>, and the magic of namespaces will take care of everything else:

Why use C?, Thanks for A2A. Let me explain what is the use of %. Actually this is the modulus operator ('%'), that computes the remainder that results from performing integer  United Security (USEC), is a private military company (PMC) and one of the main factions in Escape from Tarkov.USEC is employed by the notorious Terra Group international corporation, vigorously engages in armed clashes, hindering the investigation of Terra Group activities, carried on by local authorities.

What is the use of % in C programming?, You will need to install these tools or use those already installed on your computer. You can find more documentation on using the Microsoft C/C++ extension  Using C inline in C++ code is usually for certain modules that need to be highly optimized, do very low-level work closer to the hardware, or are critical for integrity of the data or even human safety and need to be auditable and proven correct.

Comments
  • constexpr means that the compiler can use the results during compile time. But it did not mean, that all evaluations must be done during compile time. C++ lacks the possibility to force compile time evaluation which is terrible. Some compilers complains with "expression to complex"...
  • Did you compile with optimizations? clang doesn't have the keys in the resulting assembly.
  • please see the edit
  • using namespace std; is a bad practice, never use it.
  • @tambre I do only use it to keep MWEs clean and clear ;)
  • I tried what you are saying, and it seems (strangely) that the --std=C++1z options fixes the code for me as well. Unfortunately - as stated in the question - I'm required to use C++11 for a certain project where the issue occurs. Any ideas how to fix it for C++ 11?
  • Are you sure it's not -Ofast that "fixes" the code?
  • yes, I tried it again using gcc 7.2.0 and clang-802.0.38 on macOS 10.13.1. Both omit the key strings iff I use --std=C++1z
  • strange, please see the bottom of my edit how I tested this. Maybe I'm missing something?
  • What if you try -O2? What does objdump -sghCd output?