Как определить, оценивается ли выражение во время компиляции или во время выполнения? - PullRequest
2 голосов
/ 30 апреля 2019

У меня довольно большой объект Map, и я хочу иметь отдельный список, в котором отсортированы ключи. Это будет использоваться во многих других исходных файлах моего проекта.

Вопрос в том, как мне узнать, когда декалирование / определение является заданием времени компиляции. Где мне искать, если это так? Я имею в виду, как сказать?

В следующем примере список в исходном файле является заданием времени компиляции или это происходит во время выполнения?

Кроме того, есть ли способ сделать операцию сортировки во время компиляции?

// 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 ]

6 голосов
/ 30 апреля 2019

Выражение вычисляется во время компиляции, если результат присваивается переменной constexpr, используется в операторе static_assert или noexcept или используется в качестве параметра шаблона. Это называется контекстом constexpr.

Например:

// 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);    
}

Чтобы вызвать функцию или что-то во время компиляции, она должна быть помечена constexpr.

Что вы можете сделать во время компиляции?

C ++ 11:

  • Объявлять переменные (но не изменять их)
  • Вызов других функций constexpr
  • Вызов конструкторов constexpr (и по умолчанию)
  • Используйте каретки и std::array
  • Использовать static_asserts и прочее
  • typedef и using декларации

C ++ 14 дополнений:

  • Теперь вы также можете использовать лямбды
  • Вы можете изменять переменные внутри функции constexpr
  • у вас могут быть функции-члены constexpr, которые изменяют переменные-члены
  • вы можете передавать ссылки (неконстантного вида) в функции constexpr

C ++ 20 дополнений: (C ++ 20 выйдет в 2020 году)

  • Вы можете выделить память сейчас
  • Вы можете вызывать виртуальные функции сейчас
  • Вы можете иметь try-catch блоков

Является ли std::sort constexpr?

Чтобы использовать функцию в контексте constexpr, она должна быть помечена как constexpr (которая имеет ряд ограничений на то, что вы можете делать в функции; они обсуждаются ниже). В C ++ 11 std::sort не является constexpr, потому что нарушает эти ограничения (и не будет constexpr до C ++ 20).

Однако, если вам разрешено использовать C ++ 14, вы можете написать свою собственную функцию сортировки, которая работает во время компиляции.

Полный обзор: https://en.cppreference.com/w/cpp/language/constexpr

1 голос
/ 30 апреля 2019

Кроме того, есть ли способ выполнить операцию сортировки во время компиляции?

Краткий ответ: нет.

Длинный ответ.

Нет, потому что std::sort() это constexpr только из C ++ 20 (вы пометили C ++ 11), потому что функция void (std::sort()) не может быть constexpr в C ++ 11 потому что QMap и QList не являются классами constexpr (если я не ошибаюсь), потому что вы не объявили GMAP и другие объекты, задействованные как constexpr и т. д.

Но если предположить, что класс MyMap определен constexpr, класс MyList объявлен constexpr, функция MySort() определена constexpr, вы можете написать нечто подобное (начиная с C ++ 14 потому что в C ++ 11 вы не можете написать такую ​​сложную constexpr функцию)

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

  MyList ml { ml.keys() };

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

  return ml;
}

// ...

constexpr auto ml_final { foo() };

Обратите внимание, что ml_final объявлено constexpr.

Это необходимо для навязывания (до C ++ 20) компилятора для инициализации значения времени компиляции, если это возможно, или для выдачи ошибки компиляции, если это невозможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...