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

Неоднозначный вызов перегрузки абс (двойной)

У меня есть следующий код на С++:

#include <math.h>
#include <cmath.h>      // per http://www.cplusplus.com/reference/clibrary/cmath/abs/

// snip ...

if ( (loan_balance < 0) && (abs(loan_balance) > loan_payment) ) {
    ...
}

и make срабатывает:

error: call of overloaded 'abs(double)' is ambiguous

также представляет интерес:

/usr/include/stdlib.h:785: note: candidates are: int abs(int)

Как я могу указать, что компилятор должен вызвать abs() в cmath.h, который может обрабатывать float?

Информация о компиляторе (не уверен, что это важно):

[[email protected]_box ~/some_code]#  gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr    /share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)
4b9b3361

Ответ 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()). Однако в соответствии с описанными выше трюками реализации вполне может быть. Портирование такого кода позже (или просто попытка скомпилировать его с вашей следующей версией поставщика, что не позволяет этого) может быть очень утомительным, поэтому вам следует следить за этим.

Ответ 2

Это сводится к следующему: math.h от C и был создан более 10 лет назад. В math.h из-за его примитивного характера функция abs() "по существу" предназначена только для целых типов, и если вы хотите получить абсолютное значение double, вам нужно использовать fabs(). Когда С++ был создан, он принял math.h и сделал его cmath. cmath по существу является math.h, но улучшен для С++. Он улучшил такие вещи, как необходимость различать fabs() и abs, и только что сделал abs() для обоих типов double и integer. В итоге: Используйте math.h и используйте abs() для целых чисел, fabs() для парных или использовать cmath и просто абс для всего (проще и рекомендуется)

Надеюсь, это поможет любому, у кого такая же проблема!

Ответ 3

Используйте fabs() вместо abs(), это то же самое, но для float вместо целых чисел.

Ответ 4

В моих случаях я решил эту проблему при использовании labs() вместо abs().