I have a rather big Map object and I want to have a separate list that has the keys sorted. This will be used in many other source files of my poject.

The question is about how do I know when a decalaration/definition is a compile time job. Where should I look to find if this is the case? I mean how to tell?

In the following example, is the list in the source file a compile time job or it happens at runtime?

Also, is there a way that I make the sorting operation at compile time?

// global.h    
extern QMap<int, QString> G_MAP;
extern QList<int> G_MAP_SKEYS_SORTED; 

// global.cpp
QMap<int, QString> G_MAP = { /* some hand filled (static) data */ };
QList<int> G_MAP_SKEYS_SORTED = G_MAP.keys();

// main.cpp
int mian() {
  // Somewhere I do the sort
  std::sort(G_ListRegistersSorted.begin(), G_ListRegistersSorted.end());
}

2 Answers

6
Jorge Perez On Best Solutions

An expression is evaluated at compiletime if the result is assigned to a constexpr variable, used in a static_assert or noexcept statement, or used as a template parameter. This is called a constexpr context.

For example:

// Function which can calculate the fibbonacci sequence at compiletime
constexpr int fib(int n) {
    if(n == 0 || n == 1) return n;
    return fib(n - 1) + fib(n - 2); 
}

int main() {
    // This one is calculated at compiletime
    constexpr int fib10_at_compiletime = fib(10); 

    // This one is calculated at runtime 
    // (unless the compiler was really aggressive when doing optimizations)
    int fib10_at_runtime = fib(10);    
}

In order to call a function or something at compiletime, it needs to be marked constexpr.

What can you do at compiletime?

C++11:

  • Declare variables (but not modify them)
  • Call other constexpr functions
  • Call constexpr constructors (and default ones)
  • Use carrays and std::array
  • Use static_asserts and stuff
  • typedef and using declarations

C++14 additions:

  • You can also use lambdas now
  • You can modify variables inside a constexpr function
  • you can have constexpr member functions that change member variables
  • you can pass references (the non-const kind) to constexpr functions

C++20 additions: (C++20 is coming out in 2020)

  • You can allocate memory now
  • You can call virtual functions now
  • You can have try-catch blocks

Is std::sort constexpr?

In order to use a function in a constexpr context, it must be marked constexpr (which comes with a set of restrictions on what you can do in the function; these are discussed below). In C++11, std::sort isn’t constexpr because it breaks those restrictions (and it won’t be constexpr until C++20).

However, if you’re allowed to use C++14, you can write your own sorting function that works at compile time.

Full overview: https://en.cppreference.com/w/cpp/language/constexpr

1
max66 On

Also, is there a way that I make the sorting operation at compile time?

Short answer: no.

Long answer.

No because std::sort() is constexpr only from C++20 (you tagged C++11), because a void function (std::sort()) can't be constexpr in C++11, because QMap and QList aren't constexpr classes (if I'm not wrong), because you haven't declared GMAP and other object involved as constexpr, etc.

But, supposing to have a MyMap class defined constexpr, a MyList class declared constexpr, a MySort() function defined constexpr, you could write something similar (starting from C++14 because in C++11 you can't write a so complex constexpr function)

constexpr MyList foo ()
{
  MyMap mm { /* some values */ };

  MyList ml { ml.keys() };

  MySort(ml.begin(), ml.end());

  return ml;
}

// ...

constexpr auto ml_final { foo() };

Observe that ml_final is declared constexpr.

This is necessary to impose (pre C++20) the compiler to initialize the value compile-time, if possible, or give a compilation error, if impossible.