On Tue, 6 May 2025 at 09:14, Greg Troxel <g...@lexort.com> wrote: > > I recently had trouble with code in proj, which used abs() from C++, > expecting it to be double instead of int. Changing to std::abs() fixed > it. > > That brought up the question of what the rules are. In C, abs() is > solidly integer: > > #include <stdlib.h> > > int > abs(int x); > > and there is fabs() > > #include <math.h> > > double > fabs(double x); > > But C++ is different. The standard approach is <cmath> and std::abs(), > but I find claims that C++11 requires that <cmath> make (bare) abs() > overloaded, and claims that C++11 permits but does not require it.
The "accepted answer" claims that in C++11+ <cmath> may expose std::abs;. Looking at your results it seems that LLVM+? did this, but GCC+GLIBCXX did not (which probably explains why the standard says what it says). Here NetBSD can hide behind debian. For <math.h>. The linux's have a the glibc++ with its local copy of <math.h> that I think, reduces to: # include <cmath> use std::abs; the results show both CLANG+? and GCC+glibc++ agreeing on this quirk. I suspect NetBSD may be able to argue the moral high ground, but that's little use. BTW, the "accepted answer"'s suggestion of using <stdlib.h> and abs() is just as broken as <math.h>. > In practice, it seems clear that the only reasonable coding approach is > to include <cmath> and then use std::abs() but the standards question > remains. Agreed. > I found a test program, enhanced it, and ran it on 5 systems, with > varying results. > > Is NetBSD wrong here? Or is not overloading abs() permissible? > Is Debian wrong? How is "none" compiling? Presumably #include <iostream> is up to no good, see appended. > c++ -Wall cpp_abs.cpp; ./a.out > > none math.h cmath both both/R > NetBSD/gcc7 1 1 1 1 1 > NetBSD/gcc10 1 1 1 1 1 > Debian/gcc12 1 1.5 1 1.5 1.5 Alpine (musl) and Fedora with newer GCC's match this, see appended. > macOS 10.13 DNC DNC 1.5 1.5 1.5 clang <= 18? based on appended; also freebsd with clang > macOS 13 1.5 1.5 1.5 1.5 1.5 clang >18? but could be a a header change -- Alpine and fedora with much newer GCCs [root@alpine source]# g++ -Wall -Wextra -Werror abs.cc && ./a.out abs.cc: In function 'void abses(double, double*, double*)': abs.cc:21:9: error: 'abs' was not declared in this scope 21 | *ax = abs(x); | ^~~ abs.cc:22:15: error: 'abs' is not a member of 'std' 22 | *sax = std::abs(x); | ^~~ [root@alpine source 1]# g++ -Wall -Wextra -Werror abs.cc -DUSE_MATH && ./a.out x=-1.5 ax=1.5 sax=1.5 [root@alpine source]# g++ -Wall -Wextra -Werror abs.cc -DUSE_CMATH && ./a.out x=-1.5 ax=1 sax=1.5 [root@alpine source]# g++ -Wall -Wextra -Werror abs.cc -DUSE_MATH_CMATH && ./a.out x=-1.5 ax=1.5 sax=1.5 [root@alpine source]# g++ -Wall -Wextra -Werror abs.cc -DUSE_CMATH_MATH && ./a.out x=-1.5 ax=1.5 sax=1.5 [root@alpine source]# g++ --version g++ (Alpine 14.2.0) 14.2.0 cagney@fedora:~$ c++ --version c++ (GCC) 15.1.1 20250425 (Red Hat 15.1.1-1) [root@freebsd source]# c++ -Wall -Wextra -Werror abs.cc && ./a.out abs.cc:21:9: error: use of undeclared identifier 'abs' 21 | *ax = abs(x); | ^ abs.cc:22:10: error: use of undeclared identifier 'std' 22 | *sax = std::abs(x); | ^ 2 errors generated. [root@freebsd source 1]# c++ -Wall -Wextra -Werror abs.cc -DUSE_MATH && ./a.out abs.cc:22:10: error: no member named 'abs' in namespace 'std'; did you mean simply 'abs'? 22 | *sax = std::abs(x); | ^~~~~~~~ | abs /usr/include/c++/v1/stdlib.h:127:64: note: 'abs' declared here 127 | _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI long double abs(long double __lcpp_x) _NOEXCEPT { | ^ 1 error generated. [root@freebsd source 1]# c++ -Wall -Wextra -Werror abs.cc -DUSE_CMATH && ./a.out x=-1.5 ax=1.5 sax=1.5 [root@freebsd source]# c++ -Wall -Wextra -Werror abs.cc -DUSE_MATH_CMATH && ./a.out x=-1.5 ax=1.5 sax=1.5 [root@freebsd source]# c++ -Wall -Wextra -Werror abs.cc -DUSE_CMATH_MATH && ./a.out x=-1.5 ax=1.5 sax=1.5 [root@freebsd source]# c++ --version FreeBSD clang version 18.1.6 (https://github.com/llvm/llvm-project.git llvmorg-18.1.6-0-g1118c2e05e67) #ifdef USE_MATH #include <math.h> #endif #ifdef USE_CMATH #include <cmath> #endif #ifdef USE_MATH_CMATH #include <math.h> #include <cmath> #endif #ifdef USE_CMATH_MATH #include <cmath> #include <math.h> #endif static void abses(double x, double *ax, double *sax) { *ax = abs(x); *sax = std::abs(x); } #include <iostream> int main(int, const char *[]) { double x = -1.5; double ax; double sax; abses(x, &ax, &sax); std::cout << "x=" << x << " ax=" << ax << " sax=" << sax << std::endl; return 0; }