Как эффективно отлаживать функции constexpr?

В С++ 14 мы получаем обновленную версию constexpr, что означает, что теперь можно будет использовать циклы, if-statement и переключатель. Рекурсия уже возможна, как в С++ 11.

Я понимаю, что функции/код constexpr должны быть довольно простыми, но все же возникает вопрос: как эффективно отлаживать его?

Даже в "языке программирования С++, 4-е издание" есть предложение, которое может быть затруднено debuggig.

Ответ 1

Есть два важных аспекта для отладки функций constexpr.

1) Убедитесь, что они вычисляют правильный результат

Здесь вы можете использовать регулярные модульные тесты, утверждения или отладчик времени выполнения для выполнения вашего кода. Нет ничего нового по сравнению с тестированием регулярных функций здесь.

2) Убедитесь, что они могут быть оценены во время компиляции

Это можно проверить, оценив функцию как правую часть назначения переменной constexpr.

constexpr auto my_var = my_fun(my_arg);

Для того, чтобы это сработало, my_fun может a) имеет только выражение постоянной времени компиляции как фактические аргументы. То есть my_arg является литералом (встроенным или определяемым пользователем) или ранее вычисленной переменной constexpr или параметром шаблона и т.д., и b) он может вызывать только функции constexpr в своей реализации (поэтому нет виртуальных машин, никаких лямбда-выражений и т.д.).

Примечание: очень сложно фактически отлаживать реализацию компилятора генерации кода во время оценки времени компиляции вашей функции constexpr. Вам нужно будет подключить отладчик к вашему компилятору и фактически иметь возможность интерпретировать путь кода. Возможно, какая-то будущая версия Clang позволит вам сделать это, но это невозможно для текущей технологии.

К счастью, поскольку вы можете отделить выполнение и функции времени constexpr во время выполнения и компиляции, отладка их не так сложна, как отладка шаблонов шаблонов (которые могут выполняться только во время компиляции).

Ответ 2

Если по отладке вы имеете в виду "сообщить, что определенное выражение не имеет желаемого значения", вы можете проверить его во время выполнения

#include <stdexcept>
#include <iostream>

constexpr int test(int x){ return x> 0 ? x : (throw std::domain_error("wtf")); }

int main()
{
  test(42);
  std::cout<< "42\n";
  test(-1);
  std::cout<< "-1\n";
}

Ответ 3

Вот мое предложение.

Создайте макрос:

#ifdef NDEBUG
#define OPTIONAL_CONSTEXPR constexpr
#else
#define OPTIONAL_CONSTEXPR
#endif

и замените код, например

constexpr int x;

с

OPTIONAL_CONSTEXPR int x;

Затем, если вы отлаживаете, вы сможете войти в код. Но когда вы компилируете в режиме освобождения, вы получите полную выгоду от constexpr.

Ответ 4

Ответ, который я написал 3 апреля '15, явно ошибочен. Я не могу понять, о чем я думал.

Вот "реальный" ответ - метод, который я использую сейчас.

a) напишите свою функцию constexpr, как обычно. Пока это не работает.

b), когда функция вызывается во время компиляции - компиляция завершается с не более чем сообщением о влиянии функции "недопустимый constexpr". Это затрудняет понимание сути проблемы.

c) Сделайте небольшую программу тестирования, которая вызывает функцию с параметрами, известными только во время выполнения. Запустите тестовую программу с помощью отладчика. Вы обнаружите, что вы можете проследить эту функцию обычным образом.

Мне потребовалось довольно долгое время, чтобы понять это.