Abs vs std:: abs, что говорит ссылка?

Остерегайтесь, я говорю о ::abs(), а не std::abs()

Согласно сайту cplusplus.com, abs должен вести себя по-другому для версии stdlib. h C, если вы включили <cmath>

Вот выдержка из этой страницы (которая касается ::abs, а не std::abs):

double abs (double x); 
float abs (float x); 
long double abs (long double x);
Compute absolute value
/*
Returns the absolute value of x: |x|.
These convenience abs overloads are exclusive of C++. In C, abs is only declared
in  <cstdlib> (and operates on int values). 
The additional overloads are provided in this header (<cmath>) for the integral types: 
These overloads effectively cast x to a double before calculations 
(defined for T being any integral type).
*/

Действительно???

Я был укушен этим при переносе программы на новую платформу, так как здесь различаются разные компиляторы и стандартные библиотеки.

Вот моя примерная программа:

#include <iostream>
//#include <stdlib.h>//Necessary inclusion compil under linux
//You can include either cmath or math.h, the result is the same
//#include <cmath>
#include <math.h>
int main(int argc, const char * argv[])
{
  double x = -1.5;
  double ax = std::abs(x);
  std::cout << "x=" << x << " ax=" << ax << std::endl;
  return 0;
}

И вот результат в MSVC 2010:

  • В MSVC 2010 не выдается предупреждение о компиляции, и программа будет скомпилирована, даже если вы не включаете ни math.h, ни stdlib.h: кажется, что math.h и stdlib.h всегда включены независимо от того, что вы делаете
  • Выход программы: x=-1.5 ax=1.5 (по-видимому, правильный в соответствии с эталоном)

Теперь вот результат под OSX:

  • Отсутствует предупреждение о компиляции, даже с флагом -Wall (двойное наложение не сигнализируется)! Результат будет таким же, если вы замените g++ на llvm-g++. Вложение math.h или cmath не требуется для компиляции.
  • Выход программы: x=-1.5 ax=1

И, наконец, результат под Linux:

  • Программа не будет компилироваться, если stdlib.h не будет включен (наконец, один компилятор, который не включает stdlib автоматически). Предупреждение о компиляции не выбрано для двойного → int cast.
  • Выход программы: x=-1.5 ax=1

Здесь нет явного победителя. Я знаю, что очевидным ответом является "от std::abs до ::abs", но мне интересно:

  • Является ли сайт cplusplus.com здесь, когда говорится, что abs должен автоматически предоставлять двойную версию за пределами пространства имен std?
  • Не все ли компилятор и их стандартные библиотеки здесь, кроме MSVC (хотя он включает в себя math.h молча)?

Ответ 1

Официальные ссылки говорят... это беспорядок. Pre-С++ 11 и C11:

  • Официально, включая <cmath> ничего не вводить в ::; все функции были в std::. Практически только export был менее уважаем, а разные составители разные вещи. Если вы включили <cmath>, вы использовали std:: везде или что вы получили от компилятора от компилятора.

  • C не обеспечивал никаких перегрузок: abs взял int и был объявленный в <stdlib.h>, fabs взял double и был объявлено в <math.h>.

  • Если вы включили <math.h> в С++, то не понятно, что вы но, поскольку ни один из исполнителей, похоже, не заботился о стандарт в любом случае (см. первый пункт выше)...

Грубо говоря, либо вы включили <cmath>, либо префикс все использования с std::, или вы включили <math.h>, и использовал fabs, если вам нужна поддержка плавающей запятой (и различные суффиксы для типов, отличных от int или double).

С++ 11 и C11 добавили несколько новых поворотов:

  • <cmath> теперь разрешено (но не обязательно), чтобы ввести символы в ::. Еще одна вещь, которая может меняться в зависимости от реализации. (Цель заключалась в том, чтобы существующие реализации соответствуют.)

  • C имеет новый заголовок <tgmath.h>, который использует магию компилятора для заставить функции в <math.h> вести себя так, как если бы они были перегружен как на С++. (Так что это не относится к abs, но только до fabs.) Этот заголовок не был добавлен в С++, для очевидная причина того, что С++ не нуждается в магии компилятора для это.

В целом ситуация немного ухудшилась, и моя вышеприведенные рекомендации. Включите либо <math.h>, либо <stdlib.h> и использовать abs/fabs, и их производные (например, labs, fabsf и т.д.), или включают <cmath>, и используйте std::abs исключительно. Что-нибудь еще, и вы столкнетесь проблемы с портами.