Подтвердить что ты не робот

Требует ли в стандарте С++ `#include <math.h>` для определения перегрузок `abs`, найденных в` <cmath> `?

Стандарт С++ определяет некоторые перегруженные функции в заголовке <cmath>, которые не являются частью заголовка <math.h> в C (потому что C не имеет перегрузки). Среди них float abs(float), double abs(double), long double abs(long double) и double abs(Integral). С другой стороны, abs вообще не определяется в C <math.h> (он вместо этого находится в <stdlib.h>), а единственная сигнатура - int abs(int).

Теперь в моих системах при использовании компилятора С++ с программой на С++ #include <math.h> не предоставляет перегрузки С++ abs, либо в глобальном пространстве имен, либо в std. С другой стороны, #include <cmath> определяет std::abs.

Это то, что я ожидаю, - включить версию C для получения C-функций и включить версию С++ для получения функций С++. Этот ответ от @visitor упоминает одно и то же.

Однако пользователь @Cheers-and-hth-Alf утверждает, что это является нарушением стандарта, потому что он говорит: "Каждый заголовок C, каждый из которых имеет имя формы name.h, ведет себя так, как будто каждое имя помещенный в стандартное пространство имен библиотек соответствующим заголовком cname, помещается в область глобального пространства имен." (Этот раздел, D.5.2, похоже, не сильно изменился между С++ 03, С++ 11 и С++ 14.)

Достаточно легко проверить, что делает ваша платформа: посмотреть, что происходит с

#include <math.h>

int main() {
    abs(1.2);
    return 0;
}

Если abs не объявлено, то <math.h> не включает функции С++.

Если он компилируется, попробуйте включить <stdio.h> и добавьте printf("%g\n", abs(1.2)); Если это жалуется на несоответствующий формат или печатает 1, тогда <math.h> включает функцию C int abs(int) (обычно в <stdlib.h>). (Лучше избегать <iostream> и других заголовков С++, так как они склонны тянуть <cstdlib> и путать проблему.)

Вот что я нашел:

GNU libstdС++

$ g++ -Wall -Wextra abs2.cc -o abs2
abs2.cc: In function 'int main()':
abs2.cc:5:22: error: 'abs' was not declared in this scope
  std::cout << abs(1.2) << '\n';

libstdС++ docs по теме рекомендуется включать заголовки типа С++ <c*>, а не заголовки C-стиля <*.h> именно потому, что Заголовки в стиле С++ используют перегрузку функций, а заголовки в стиле C - нет.

Apple libС++

$ clang++ -Wall -Wextra abs2.cc -o abs2
abs2.cc:4:5: error: use of undeclared identifier 'abs'; did you mean 'fabs'?

Кроме того, если вы также включаете <stdlib.h>, чтобы получить определение abs, clang++ дает более полезное сообщение об ошибке

abs2.cc:5:5: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
    abs(1.2);
    ^
abs2.cc:5:5: note: use function 'std::abs' instead
    abs(1.2);
    ^~~
    std::abs
abs2.cc:5:5: note: include the header <cmath> or explicitly provide a declaration for 'std::abs'
abs2.cc:5:9: warning: implicit conversion from 'double' to 'int' changes value from 1.2 to 1 [-Wliteral-conversion]
    abs(1.2);
    ~~~ ^~~
abs2.cc:5:5: warning: ignoring return value of function declared with const attribute [-Wunused-value]
    abs(1.2);
    ^~~ ~~~

Это явно говорит о том, что перегрузки поплавка доступны только из <cmath>, а не из C традиционными заголовками.

Apache libstdcxx

Я не установил его, но рассмотрев заголовок math.h, он возвращает те функции из <cmath>, которые также определены в C <math.h> в глобальное пространство имен, но не включает abs.

OpenWatcom С++

Опять же, рассмотрев cmath/math.h header, при использовании в качестве math.h он вносит те же функции в глобальное пространство имен, что и Apache libstdcxx, не включая abs.

STLPort

Изучая заголовок math.h, он включает в себя заголовок системы C <math.h>, который не является частью библиотеки С++ и поэтому не включает abs. (Это то же, что и g++ и clang++).

Microsoft Visual Studio (Dinkumware)

У меня нет доступа к этому самому, но этот сайт претендует на компиляцию с использованием Visual С++, и он говорит

error C4578: 'abs': conversion from 'double' to 'int', possible loss of data
(Did you mean to call 'fabs' or to #include <cmath>?) 

Итак, буквально каждая основная реализация стандартной библиотеки С++ в нарушение стандарта по этому вопросу?

Или нам не хватает чего-то, что стандарт говорит о <math.h> и других традиционных заголовках C?

4b9b3361

Ответ 1

"Каждый заголовок C, каждый из которых имеет имя формы name.h, ведет себя так, как будто каждое имя, помещенное в пространство имен стандартной библиотеки соответствующим заголовком cname, помещается в область глобального пространства имен."

Эта формулировка для меня не говорит о том, что каждое имя в заголовке <cname> должно появляться в заголовке name.h.

В нем говорится, что каждое имя в заголовке <name.h> , имеющее соответствующее имя в заголовке <cname>, должно отображаться в глобальном пространстве имен.

Он ничего не говорит об именах в заголовке <cname>, которые не отображаются в заголовке <name.h>.

С++ 14 Stadard

D.5 C стандартные заголовки библиотек [ des.c.headers ]

Для совместимости со стандартной библиотекой C и C Unicode TR стандартная библиотека С++ предоставляет заголовки 26 C, как показано в таблице

В этом утверждении используется термин "заголовки 26 C", в котором говорится, что они содержат то, что говорит C-стандарт, который должен содержать, а не стандарт C++, который должен содержать <cname>.

Действительно, в отношении <cstddef>, например, он детализирует элементы, не содержащиеся в соответствующем заголовке C.

например,

18.2 Типы [ support.types ]

2 Содержимое совпадает с заголовком библиотеки стандартного C <stddef.h> со следующими изменениями...