#c #compilation #c 14 #static-assert
#c #Сборник #c 14 #статическое утверждение
Вопрос:
Я написал несколько математических функций времени компиляции в заголовочном файле утилиты и использую static_assert
инструкции для их тестирования.
Следует ли сохранять эти инструкции в производственном коде или в тестовом коде (в фиктивном «модульном тестировании» * .cpp), вероятно, в основном зависит от стиля / предпочтений (хотя комментарии приветствуются).
Но как насчет производительности (времени компиляции), если у нас было много тестов? Если я сохраню static_assert
в заголовке производственного кода, будут ли они выполняться для каждого модуля компиляции, в который я включаю заголовок? Или компилятор каким-то образом «умен» в отношении static_assert
операторов?
Одна из наиболее тривиальных функций в качестве примера:
/** Calculate the sum of a given number of args in parameter pack - starting from the given firstSummand (1-based) */
template<typename... Args, typename T = typename std::common_type<Args...>::type>
constexpr T sumOverRange(int firstSummand, int numSummands, Args... args) noexcept
{
firstSummand = std::max<int>(firstSummand, 1);
numSummands = std::min<int>(numSummands, sizeof...(args)-firstElement 1);
T sum {0};
T values[] { args... };
for (int i=firstSummand; i < firstSummand numSummands; i) {
sum = values[i-1];
}
return sum;
}
static_assert(sumOverRange(2, 3, 2, 2, 3, -4) == 1, "");
static_assert(sumOverRange(1, 0, 2, 2, 3) == 0, "zero summands");
static_assert(sumOverRange(2, -1, 2, 2, 3) == 0, "negative num summands");
static_assert(sumOverRange(-1, 1, 2, 2, 3) == 2, "negative range start");
Комментарии:
1. Почему бы просто не использовать защиту включения? Подождите, вы спрашиваете о включении заголовка дважды в один и тот же исходный файл или о включении его в отдельные исходные файлы, скомпилированные отдельно?
2. Я, конечно, использую защиту включения — я имею в виду в отдельных блоках компиляции…
3. Я бы измерил это.
Ответ №1:
Если я сохраню static_assert в заголовке производственного кода, будут ли они выполняться для каждого модуля компиляции, в который я включаю заголовок?
ДА. Включение не делает ничего другого, кроме вставки содержимого включаемого файла во включаемый файл. Для компилятора C нет разницы, берется ли ваш код из заголовка или нет. Следовательно, static_assert всегда будет оцениваться.
Или компилятор каким-то образом «умен» в отношении static_assert-операторов?
Это может быть. Но большинство компиляторов, вероятно, не очень разбираются в этом, поскольку в центре внимания при разработке компиляторов традиционно были быстрые исполняемые файлы, а не быстрая оценка программ во время компиляции.
Но как насчет производительности (времени компиляции), если у нас было много тестов?
Что ж, компилятору придется выполнить ваш код. Вероятно, это будет медленнее, чем компиляция и запуск соответствующего кода за абсолютное время, но асимптотически так же быстро.
Возможно, вас заинтересует это обсуждение: https://lists.llvm.org/pipermail/cfe-dev/2019-July/062799.html
В качестве практической рекомендации: поскольку вы, по-видимому, используете static_asserts для модульного тестирования своего кода, я бы рекомендовал удалить их из заголовка. Тесты всегда должны быть отделены от тестируемого кода.