Skip to content

Latest commit

 

History

History
133 lines (113 loc) · 3.45 KB

README.md

File metadata and controls

133 lines (113 loc) · 3.45 KB

How to use constexpr, but probably not for fame and profit

Constants are one of the evolutions from "#define" of the C world but have many more uses.

  • Whereas a "#define" would not be visible in the debugger, consts have the potential to be so.
  • Consts (static ones) can also be optimized by the linker to take up no store space.
  • And of course they make your code more readable and safer.

However they have limits. You can do all the below with just const:

    #include <iostream>

    auto what_is_the (int meaning, int of) {
        meaning++;
        return meaning * of;
    }

    const auto meaning = 5;
    const auto of = 7;
    const auto life = what_is_the(meaning, of);

    int main(void) {
        std::cout << "the meaning is " << life << std::endl;
        return 0;
    }

But you would not be allowed to do this:

    int what_is_the (int meaning, int of) {
        meaning++;
        return meaning * of;
    }
    const int life = what_is_the(meaning, of);

However if you add "constexpr" then bingo:

    constexpr int what_is_the (int meaning, int of) {
        meaning++;
        return meaning * of;
    }
    const int life = what_is_the(meaning, of);

If you wish a constexpr to be visible to other modules at link time then you must do the following at the point of declaration of the constexpr:

    extern constexpr auto the_universe = TheUniverse(sizeof(the_earth) * planets);

If you try the below you should see the symbol:

    c++ -std=c++2a -Werror -g -ggdb3 -Wall -c -o main.o main.cpp
    c++ main.o  -o example
    nm -gU example | grep _the_universe
    0000000100001ea4 S _the_universe

If you want to have a constexpr in a header file made visible to other files you are compiling you can use the concept of "C++17 inline variables":

    inline constexpr int the_meaning_of = 42;

See this link for more information.

So in summary:

  • const means ‘‘I promise not to change this value’’
  • constexpr means ‘‘to be evaluated at compile time’’

Ok, here is a silly example:

#include <iostream>

class TheUniverse
{
private:
  int size;

public:
  constexpr TheUniverse(int size) : size(size) {}
  constexpr int get_size() const { return (size); }
};

constexpr auto what_is_the(int meaning, int of)
{
  meaning++;
  return meaning * of;
}

// const works just as well here for all the below
constexpr auto meaning = 5;
constexpr auto of      = 7;
constexpr auto life    = what_is_the(meaning, of);
constexpr auto planets = 100000;
constexpr char the_earth[ life ] {};

//
// Note using constexpr will make this symbol visible in the linker
//
constexpr auto the_universe = TheUniverse(sizeof(the_earth) * planets);

int main(void)
{
  // What is the meaning...:
  std::cout << "the meaning is " << life << std::endl;

  // How big is the earth...:
  std::cout << sizeof(the_earth) << std::endl;

  // How big is the universe...:
  std::cout << the_universe.get_size() << std::endl;

  return 0;
}

To build:

cd constexpr
rm -f *.o example
clang -std=c++2a -Werror -g -O3 -fstack-protector-all -ggdb3 -Wall -c -o main.o main.cpp
clang  main.o -lstdc++  -o example
./example

Expected output:

�[31;1;4mWhat is the meaning...:�[0m
the meaning is 42

�[31;1;4mHow big is the earth...:�[0m
42

�[31;1;4mHow big is the universe...:�[0m
4200000