Ответ 1
Заголовок <math.h>
является заголовком C std lib. Он определяет много вещей в глобальном пространстве имен. Заголовок <cmath>
- это С++-версия этого заголовка. Он определяет по существу тот же самый материал в пространстве имен std
. (Есть некоторые отличия, например, версия С++ поставляется с перегрузками некоторых функций, но это не имеет значения.) Заголовок <cmath.h>
не существует.
Поскольку поставщики не хотят поддерживать две версии того, что по сути является одним и тем же заголовком, они придумали разные возможности, чтобы иметь только одну из них за кулисами. Часто, что заголовок C (поскольку компилятор С++ способен разобрать это, в то время как противоположное не будет работать), а заголовок С++ включает это и вытаскивает все в пространство имен std
. Или есть макрос магии для разбора одного и того же заголовка с или без namespace std
, обернутых вокруг него или нет. Для этого добавьте, что в некоторых средах это неудобно, если заголовки не имеют расширения файла (например, редакторы не могут выделить код и т.д.). Таким образом, некоторые поставщики имели бы <cmath>
как однострочный, включая другой заголовок с расширением .h
. Или некоторые из них будут отображать все, включая сопоставление <cblah>
с <blah.h>
(которое с помощью макроса становится заголовком С++, когда __cplusplus
определено и в противном случае становится заголовком C) или <cblah.h>
или что-то еще.
По этой причине на некоторых платформах, включая такие, как <cmath.h>
, которые не должны существовать, изначально удастся, хотя это может привести к тому, что компилятор не будет эффектно позже.
Я не знаю, какую версию std lib вы используете. Я предполагаю, что это тот, который поставляется с GCC, но этого я не знаю, поэтому я не могу точно объяснить, что произошло в вашем случае. Но это, безусловно, сочетание одного из вышеупомянутых хакеров, связанных с продавцом, и вы включаете заголовок, который вы не должны были включать в себя. Возможно, это тот, где <cmath>
отображается на <cmath.h>
с определенным (набором) макросов, которые вы не определили, так что вы оказались с обоими определениями.
Обратите внимание, что этот код еще не должен компилироваться:
#include <cmath>
double f(double d)
{
return abs(d);
}
В глобальном пространстве имен не должно быть abs()
(it std::abs()
). Однако в соответствии с описанными выше трюками реализации вполне может быть. Портирование такого кода позже (или просто попытка скомпилировать его с вашей следующей версией поставщика, что не позволяет этого) может быть очень утомительным, поэтому вам следует следить за этим.