static_assert в заголовке производственного кода: плохо для времени компиляции?

#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 для модульного тестирования своего кода, я бы рекомендовал удалить их из заголовка. Тесты всегда должны быть отделены от тестируемого кода.