2009-09-03 33 views
47

Tôi có C++ mã sau:quá tải gọi mơ hồ để abs (double)

#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 thổi lên trên:

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

cũng quan tâm:

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

Làm thế nào tôi có thể chỉ định rằng trình biên dịch cần phải gọi abs() trong cmath.h có thể xử lý nổi?

thông tin Compiler (Không chắc chắn nếu vấn đề này):

[[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

Trang cplusplus bạn trích dẫn không nói để bao gồm cmath.h. Nó nói cmath. Đó là phiên bản C++ của math.h. Không bao gồm cả hai. –

Trả lời

42

Tiêu đề <math.h> là một C std lib tiêu đề. Nó định nghĩa rất nhiều thứ trong không gian tên chung. Tiêu đề <cmath> là phiên bản C++ của tiêu đề đó. Nó định nghĩa về cơ bản những thứ giống nhau trong không gian tên std. (Có một số khác biệt, giống như phiên bản C++ đi kèm với quá tải của một số chức năng, nhưng điều đó không quan trọng.) Đầu trang <cmath.h> không tồn tại.

Vì các nhà cung cấp không muốn duy trì hai phiên bản về cơ bản là cùng một tiêu đề, nên chúng có nhiều khả năng khác nhau để chỉ có một trong số chúng ở hậu trường. Thông thường, đó là tiêu đề C (vì trình biên dịch C++ có thể phân tích cú pháp đó, trong khi đối diện sẽ không hoạt động), và tiêu đề C++ chỉ bao gồm và kéo mọi thứ vào không gian tên std. Hoặc có một số phép thuật vĩ mô để phân tích cú pháp cùng một tiêu đề có hoặc không có namespace std quấn quanh nó hay không. Để điều này thêm rằng trong một số môi trường nó là khó xử nếu tiêu đề không có một phần mở rộng tập tin (như biên tập viên không làm nổi bật mã vv). Vì vậy, một số nhà cung cấp sẽ có <cmath> là một lớp lót bao gồm một số tiêu đề khác có phần mở rộng là .h. Hoặc một số bản đồ tất cả sẽ bao gồm kết hợp <cblah> đến <blah.h> (trong đó, thông qua ma thuật macro, trở thành tiêu đề C++ khi __cplusplus được xác định và nếu không trở thành tiêu đề C) hoặc <cblah.h> hoặc bất kỳ thứ gì.

Đó là lý do tại sao trên một số nền tảng bao gồm những thứ như <cmath.h>, không nên tồn tại, ban đầu sẽ thành công, mặc dù nó có thể khiến trình biên dịch thất bại sau này.

Tôi không biết bạn triển khai thực thi lib nào. Tôi cho rằng đó là một trong đó đi kèm với GCC, nhưng điều này tôi không biết, vì vậy tôi không thể giải thích chính xác những gì đã xảy ra trong trường hợp của bạn. Nhưng nó chắc chắn là một kết hợp của một trong những nhà cung cấp cụ thể trên hacks và bạn bao gồm một tiêu đề bạn nên không có bao gồm chính mình. Có thể đó là nơi mà <cmath> ánh xạ tới <cmath.h> với một (các) macro cụ thể mà bạn chưa xác định, do đó bạn đã kết thúc bằng cả hai định nghĩa.

Lưu ý, tuy nhiên, mã này vẫn không nên biên dịch:

#include <cmath> 

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

Có nên không phải là một abs() trong không gian tên toàn cầu (đó là std::abs()). Tuy nhiên, theo các thủ thuật thực hiện được mô tả ở trên, cũng có thể có. Chuyển mã sau đó (hoặc chỉ cố gắng biên dịch mã với phiên bản tiếp theo của nhà cung cấp mà không cho phép điều này) có thể là rất tẻ nhạt, vì vậy bạn nên theo dõi điều này.

30

Điểm của nó là: math.h là từ C và được tạo hơn 10 năm trước. Trong math.h, do tính chất nguyên thủy của nó, hàm abs() là "cơ bản" chỉ dành cho các kiểu số nguyên và nếu bạn muốn nhận giá trị tuyệt đối của một đôi, bạn phải sử dụng fabs(). Khi C++ được tạo, nó mất math.h và làm cho nó cmath. cmath về cơ bản là math.h nhưng được cải thiện cho C++. Nó cải thiện những thứ như phải phân biệt giữa fabs() và abs, và chỉ cần thực hiện abs() cho cả hai loại tăng gấp đôi và số nguyên. Nói tóm lại trong hai: Sử dụng math.h và sử dụng abs() cho số nguyên, fabs() cho đôi hoặc sử dụng cmath và chỉ có abs cho tất cả mọi thứ (dễ dàng hơn và khuyến khích)

Hope this helps bất cứ ai đang gặp vấn đề tương tự!

11

Sử dụng fabs() thay vì abs(), nó giống nhau nhưng đối với phao thay vì số nguyên.

+6

không thực sự chính xác trong không gian tên 'std', trong đó' abs' quá tải cho 'float',' double', v.v. – Flexo

+0

lỗi gcc6 cố định: cuộc gọi quá tải 'abs (uint32_t)' không rõ ràng –

+0

@ Sérgio Tôi nghĩ bạn chỉ cần loại bỏ cuộc gọi đến abs, vì uint32_t chưa được ký. (Thay vào đó bạn hoàn toàn đúc uint32_t để tăng gấp đôi cho fabs (double) và sau đó tôi giả định kết quả quay trở lại một số nguyên!) – Raptor007

Các vấn đề liên quan