Как эффективно отлаживать функции 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) Сделайте небольшую программу тестирования, которая вызывает функцию с параметрами, известными только во время выполнения. Запустите тестовую программу с помощью отладчика. Вы обнаружите, что вы можете проследить эту функцию обычным образом.
Мне потребовалось довольно долгое время, чтобы понять это.