2009-09-03 21 views
47

Mam następujący C++ kod:Niejednoznaczne wezwanie przeciążenie do ABS (podwójne)

#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)) { 
    ... 
} 

i make wysadza na:

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

także interesujące:

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

Jak mogę określić, że kompilator musi wywoływać abs() w cmath.h, który może obsługiwać pływaki?

Compiler informacji (nie wiem, czy to ma znaczenie):

[[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) 
+6

Strona cplusplus, którą cytujesz, nie zawiera cmath.h. Mówi cmath. To jest wersja C++ dla math.h. Nie dołączaj obu. –

Odpowiedz

42

Nagłówek <math.h> jest C std lib nagłówka. Definiuje wiele rzeczy w globalnej przestrzeni nazw. Nagłówek <cmath> jest wersją C++ tego nagłówka. Definiuje zasadniczo te same rzeczy w przestrzeni nazw std. (Są pewne różnice, na przykład wersja C++ zawiera przeciążenia niektórych funkcji, ale to nie ma znaczenia.) Nagłówek <cmath.h> nie istnieje.

Ponieważ dostawcy nie chcą utrzymywać dwóch wersji tego samego nagłówka, wymyślili różne możliwości posiadania tylko jednego z nich za kulisami. Często jest to nagłówek C (ponieważ kompilator C++ jest w stanie to przeanalizować, podczas gdy przeciwieństwo nie działa), a nagłówek C++ po prostu obejmuje to i przeciąga wszystko do przestrzeni nazw std. Lub istnieje trochę magii makro do parsowania tego samego nagłówka z lub bez namespace std owiniętego wokół niego, czy nie. Do tego dodać, że w niektórych środowiskach jest to niezręczne, jeśli nagłówki nie mają rozszerzenia pliku (np. Redaktorzy nie podświetlają kodu itp.). Niektórzy dostawcy mieliby więc jeden liniowiec, w tym inny nagłówek z rozszerzeniem .h. Lub niektóre z mapowałby wszystkie obejmuje dopasowanie <cblah> do <blah.h> (który, poprzez magię makro, staje się nagłówkiem C++, gdy __cplusplus jest zdefiniowany i w przeciwnym razie staje się nagłówkiem C) lub <cblah.h> lub cokolwiek innego.

To jest powód, dla którego na niektórych platformach, w tym na przykład <cmath.h>, które nie powinny istnieć, początkowo się powiedzie, chociaż może sprawić, że kompilator przestanie działać spektakularnie później.

Nie mam pojęcia, z której implementacji biblioteki STD korzystasz. Przypuszczam, że to ten, który pochodzi z GCC, ale tego nie wiem, więc nie mogę wyjaśnić dokładnie, co się stało w twoim przypadku. Ale jest to z pewnością mieszanka jednego z powyższych hacków specyficznych dla danego dostawcy, w tym nagłówek, do którego nie powinieneś się zaliczać. Może to jest ta, w której <cmath> mapuje na <cmath.h> z konkretnym (zestawem) makr, których nie zdefiniowałeś, dzięki czemu uzyskałeś obie definicje.

Należy jednak pamiętać, że ten kod nadal nie powinien skompilować:

#include <cmath> 

double f(double d) 
{ 
    return abs(d); 
} 

Tam nie powinno być abs() w globalnej przestrzeni nazw (to std::abs()). Jednak zgodnie z opisanymi powyżej sztuczkami implementacyjnymi może być. Przeniesienie takiego kodu w późniejszym czasie (lub po prostu próba skompilowania go z następną wersją Twojego dostawcy, która na to nie pozwala) może być nudne, więc powinieneś mieć to na oku.

30

Jego sprowadza się do tego: math.h pochodzi z C i został stworzony ponad 10 lat temu. W matematyce, ze względu na swój pierwotny charakter, funkcja abs() jest "zasadniczo" tylko dla typów całkowitych i jeśli chcesz uzyskać wartość bezwzględną podwójnego, musisz użyć fabs(). Po utworzeniu C++ zajęło math.h i utworzono je jako cmath. cmath jest zasadniczo math.h, ale ulepszone dla C++. Poprawiło to takie rzeczy, jak konieczność rozróżnienia pomiędzy fabs() i abs, i właśnie wykonano abs() dla typów podwójnych i całkowitych. Podsumowując albo: Zastosowanie math.h i używać abs() dla liczb całkowitych, fabs() dla deblu lub użytku cmath i po prostu mieć abs na wszystko (łatwiejsza i zalecana)

nadzieję, że to pomaga każdemu, kto jest ten sam problem!

11

Użyj fabs() zamiast abs(), to jest to samo, ale dla liczb zmiennoprzecinkowych zamiast liczb całkowitych.

+6

To nie jest dokładne w przestrzeni nazw 'std', gdzie' abs' jest przeciążone dla 'float',' double' itp. – Flexo

+0

naprawiony błąd gcc6: wywołanie przeciążonego 'abs (uint32_t)' jest niejednoznaczne –

+0

@ Sérgio Myślę, że ty powinien po prostu usunąć wywołanie abs, ponieważ uint32_t jest unsigned. (Zamiast tego domyślnie rzutujesz na uint32_t na podwójne dla fabs (double), a następnie zakładam, że rzutuję wynik z powrotem na liczbę całkowitą!) – Raptor007

Powiązane problemy