Как можно использовать Pow без включения библиотеки Cmath - PullRequest
1 голос
/ 20 апреля 2020

Я пытаюсь изучать C ++ и использую MS Visual Studio 2019. У меня есть код ниже:

#include <iostream>

int main()
{
    std::cout << pow(10, 2);
}

Как можно скомпилировать и запустить без ошибок, не включая cmath ? Внутри решения есть только один файл с указанным кодом.

Ответы [ 2 ]

6 голосов
/ 20 апреля 2020

Как в C ++ возможно использовать pow без включения библиотеки cmath

Включая другой заголовок, который включает заголовок <math.h>.

Нет гарантии, что заголовки стандартной библиотеки не будут включать в себя другие заголовки вообще, а также, что <iostream> не будет включать <cmath> в частности. Также нет гарантии, что <iostream> будет включать этот заголовок, поэтому эта программа может не скомпилироваться при использовании другой стандартной реализации библиотеки или другой ее версии.

В заключение: никогда не полагайтесь на такое транзитивное включение. Всегда напрямую включайте все заголовки, от объявлений которых вы зависите, если только переходное включение явно не указано (например, <ios> гарантированно включает <iosfwd>). Вы не можете использовать успешную компиляцию в качестве доказательства того, что вы предоставили все необходимые прямые включения.

4 голосов
/ 20 апреля 2020

Обновление : обеспокоенный комментарием @Pete Becker, я исправляю свой ответ на это:

Ваш код плохо сформирован и из-за этого вызывает так называемое неопределенное поведение не поведение, определяемое реализацией .

Однако этот вывод не является полностью безопасным, так как мы входим здесь в часть языковой адвокатуры.

Неопределенное поведение (UB) определяется как

поведение, для которого этот международный стандарт не предъявляет никаких требований, что обычно означает: не пытайтесь рассуждать об этом коде и никогда не используйте его.

Вопрос в том, определяет ли C ++ требования к вашему коду, т. е. является ли ваш код правильно сформированная программа ? Тогда это будет определенное поведение (обычное поведение), неопределенное поведение или даже квалификация этого поведения, определенного реализацией . Но в 20.5.2.2 Заголовки [using.headers] стандарт C ++ гласит:

Единица перевода должна включать заголовок только вне любого объявления или определения и должна включать заголовок лексически перед первой ссылкой в этом блоке перевода любому из объектов, объявленных в этом заголовке. Диагностика c не требуется.

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


Старая часть: простой, но неудовлетворительный ответ: так называемое поведение, определяемое реализацией. Компилятор Microsoft Visual C ++ и его заголовки могут свободно включать друг друга, возможно, заголовок MSVC iostream уже включает cmath, по крайней мере, транзитивно, если не напрямую.

Веселье начинается, если вы попытаетесь скомпилировать тот же код с помощью g cc или clang. Внезапные пропущенные включения - это, по крайней мере, наиболее распространенные переносимые ошибки в моем коде.

Если вы фактически включаете каждый заголовок, который, как говорит стандарт, требуется, то есть содержит определения того, что вы используете, вы получаете так называемый portable код , означающий код, который будет компилироваться и делать то же самое независимо от использования MSVC / Visual Studio или g cc или clang или любого другого стандартного совместимого компилятора.

...