Why is abs not in std? - c++

#include <cmath>
int abs;
int main()
{
}
This code throws the compilation error
error: 'int abs' redeclared as different kind of symbol
note: previous declaration 'int abs(int)'
The same thing happens if I include it from cstdlib.
I read this documentation https://en.cppreference.com/w/cpp/numeric/math/abs
where it is nowhere mentioned that abs would be defined outside std. In fact, it explicity mentions it as std::abs everywhere.
The same thing happens with other functions, such as sqrt.
Why is this happening? How can I use these functions without cluttering my namespace? If not possible, are there c++ alternatives?

Why is abs not in std?
Your question is slightly wrong. abs is in std. Let me assume that you're asking "Why is abs also in the global namespace?".
The C++ standard allows the C standard functions to be declared in the global namespace in addition to being declared in the std namespace.
Why is this happening?
Because those functions are from the C standard library, and because standard allows it to happen, and because of the way your standard library was implemented.
How can I use these functions without cluttering my namespace?
Those names are reserved to the language implementation in the global namespace. There's no way to avoid it.
Don't treat the global namespace as "your namespace". The global namespace is cluttered, and it always will be. You need to work around that.
If not possible, are there c++ alternatives?
The C++ alternative is to declare your abs in your namespace:
namespace my_very_own_namespace {
int abs;
}
You should declare everything1 in your own namespace, except:
That namespace itself
main
Template specialisations of names in other namespaces where that is allowed
Cross-language API's i.e. anything extern "C"
The hardest part is figuring out a unique name for your own namespace, since it mustn't be one that is already used by the C standard library, nor preferably any name used by other libraries in the global namespace.
1 Following this rule of thumb is hardly necessary when writing tiny exercise programs etc. But it becomes essential when writing large programs and relying on third party libraries, not to mention when writing those libraries for others to use.
Standard quotes:
[extern.names]
Each name from the C standard library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage,171 or as a name of namespace scope in the global namespace.
[headers]
Except as noted in [library] through [thread] and [depr], the contents of each header cname is the same as that of the corresponding header name.h as specified in the C standard library.
In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope of the namespace std.
It is unspecified whether these names (including any overloads added in [support] through [thread] and [depr]) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations ([namespace.udecl]).

Related

int abs(int) vs double abs(double) [duplicate]

This question already has answers here:
Ambiguous overload call to abs(double)
(4 answers)
Closed 12 months ago.
I'd like to understand the behavior of the following code, from the C++ Standard point of view (GCC 9.3, C++20):
#include <cstdlib>
template<class> struct type_tester;
int main() {
type_tester<decltype(abs(0.1))>{}; // int abs(int) overload is selected for some reason!
type_tester<decltype(std::abs(0.1))> {}; // double abs(double) overload is selected, as one would expect
}
So, int abs(int) is imported to the global namespace, while double abs(double) is not!
Why?
cstdlib is the C++ version of the C header stdlib.h. Such headers must introduce the names in the std namespace and they are allowed to introcude them in the global namespace. There is no double abs(double) in the C header, hence there is no reason to introduce it in the global namespace like it is done for the C variants of the funciton. Note that C has no namespaces, and having the function in the global namespace helps for compatibility with C code. For double abs(double) this is not an issue, because the function does not exist in the C header.
From cppreference:
For some of the C standard library headers of the form xxx.h, the C++
standard library both includes an identically-named header and another
header of the form cxxx (all meaningful cxxx headers are listed
above). The intended use of headers of form xxx.h is for
interoperability only. It is possible that C++ source files need to
include one of these headers in order to be valid ISO C. Source files
that are not intended to also be valid ISO C should not use any of the
C headers.
With the exception of complex.h , each xxx.h header included in the
C++ standard library places in the global namespace each name that the
corresponding cxxx header would have placed in the std namespace.
These headers are allowed to also declare the same names in the std
namespace, and the corresponding cxxx headers are allowed to also
declare the same names in the global namespace: including <cstdlib>
definitely provides std::malloc and may also provide ::malloc.
Including <stdlib.h> definitely provides ::malloc and may also provide
std::malloc. This applies even to functions and function overloads
that are not part of C standard library.
This applies even to functions and function overloads that are not part of C standard library. That means: It would be allowed to have double abs(double) in the global namespace too, but it is not required.
So, int abs(int) is imported to the global namespace,
Why?
Because the C++ standard allows it to be imported into the global namespace.
While double abs(double) is not!
Why?
Because the C++ standard doesn't require it to be imported into the global namespace.
Relevant standard quotes:
[headers]
Except as noted in [library] through [thread] and [depr], the contents of each header cname is the same as that of the corresponding header name.h as specified in the C standard library.
In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope of the namespace std.
It is unspecified whether these names (including any overloads added in [support] through [thread] and [depr]) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations ([namespace.udecl]).
Evidently, the C++ standard library implementation that you use had chosen to use the strategy described in the last paragraph of the quoted rule for the C standard library function, while having chosen not to use that strategy for the C++ standard library overloads. This specific outcome isn't guaranteed by the standard but it is conforming.
Another possible outcome would be that abs(0.1) would fail as use of an undeclared identifier. You cannot rely on C++ standard library names to be declared in the global namespace (unless you use the deprecated <name.h> C standard headers).

Can reserved function names be overloaded?

This question is a follow-up question of this one.
Consider the following program:
#include <cmath>
// meaningless, only for language-lawyer purpose
void abs(void*) {}
int main(){
abs(nullptr);
}
Does this program result in undefined behavior?
The related part in the standard is [extern.names]/4:
Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
I'm not sure whether overloading is permitted.
There are two parts to this statement, as it talks about names (from the C standard) that are reserved (for C++ implementations). In particular,
Part 1: Each function signature from the C standard library declared
with external linkage
This includes the C library function abs
Part 2: is reserved to the implementation for use as a function
signature with both extern "C" and extern "C++" linkage, or as a name
of namespace scope in the global namespace.
So the name ::abs is reserved for the C++ implementation. You can't use it. Overloading is irrelevant.
tl;dr -
yes, you can
http://www.eel.is/c++draft/reserved.names#extern.names
Pulling in the rest of the context:
20.5.4.3.2: If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
And then also
20.5.4.3.3.2 Each global function signature declared with external linkage in a header is reserved to the implementation to designate that function signature with external linkage.
20.5.4.3.3.4 Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage,182 or as a name of namespace scope in the global namespace.
These suggest you can, as it is only the signature that is reserved.
Bonus for namespace ::std
http://www.eel.is/c++draft/library#namespace.std
20.5.4.2.1.1 Unless otherwise specified, the behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std.
http://en.cppreference.com/w/cpp/language/extending_std has summarised the exceptions

pollution of global namespace by standard header files

Time and again I run into problems from namespace pollution due to indirect inclusion of C-header files from C++ standard headers. For example, on my linux system gcc's (version 5.1.1) <thread> includes usr/include/bits/sched.h, which declares
extern "C" {
extern int clone(int (*__fn) (void *__arg), void *__child_stack, int __flags, void *__arg, ...) throw();
}
In the following minimal example
#include <thread> // indirect inclusion of <sched.h>
namespace {
struct foo
{ virtual foo*clone() const=0; };
foo*clone(std::unique_ptr<foo> const&); // function intended
struct bar : foo
{
std::unique_ptr<foo> daughter;
bar(foo*d) : daughter(d) {}
foo*clone() const
{ return new bar(::clone(daughter)); } // to be called here
};
}
the compiler complains about the call to ::clone() not matching the definition from bits/sched.h (ignoring the definition just before). (Note that simply calling clone instead of ::clone clashes with the member.)
So, the questions are:
Is gcc correct to discard my version of clone() when trying to resolve the function call ::clone(daughter)?
Is the pollution of the global namespace in this way standard compliant?
In the above example, can I resolve the problem without renaming my clone() functions (or the anonymous namespace) but still including <thread>?
Is gcc correct to discard my version of clone() when trying to resolve the function call ::clone(daughter)?
Yes, I think so.
Is the pollution of the global namespace in this way standard compliant?
It's arguable. For a pure C++ implementation, no, but there aren't many of them. In practice most are "C++ on POSIX" or "C++ on Windows" implementations and declare lots of names that are not in the C++ standard.
The namespace pollution problem is well known (11196, 51749 and others), with no simple solution.
The problem is that most C++ standard library implementations don't control the C library and just include the platform's native C headers, which pull in other names.
In the above example, can I resolve the problem without renaming my clone() functions (or the anonymous namespace) but still including ?
In your specific case you can solve the name lookup problem by putting your clone overload in the global namespace so lookup finds it at the same time as the function in <sched.h> and by making it static to give it internal linkage again.
yes, because ::clone looks for clone first in the global (outermost) namespace, and then in the anonymous namespace.
Nothing prevents you (or library providers) to pollute any namespace (global included) but 'std' which is reserved for the standard.
Naming the anonymous namespace could be a way out.
If the question #2 is "Does the standard allow the pollution of global namespace by including a standard header, i.e. making available more symbols than the standard require?". Then I guess the answer is yes, otherwise the constraint imposed on standard library vendors could be too stringent.
Implementation is allowed to put definitions into the global namespace in some cases.
First, a C++ library header is allowed to include other C++ headers:
N3337 17.6.5.2 Headers [res.on.headers] P1:
A C++ header may include other C++ headers. A C++ header shall provide the declarations and definitions
that appear in its synopsis. A C++ header shown in its synopsis as including other C++ headers shall provide
the declarations and definitions that appear in the synopses of those other headers.
The included C++ header can be a wrapper for a C library. Names of these C++ headers start with c, like <cstdlib>.
These headers are allowed to put corresponding C-library definitions in the global namespace first, and then inject them into std namespace.
17.6.1.2 Headers [headers] P4:
Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same
as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode
TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for
names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is
unspecified whether these names are first declared within the global namespace scope and are then injected
into namespace std by explicit using-declarations (7.3.3).
Thus, the functions defined in the C standard library can end up in the global namespace.
The clone function, however, in not part of C standard library (it is part of POSIX standard) and thus not formally allowed to appear in the global namespace by the C++ standard.

Legacy standard C library headers and overloaded C++ functions

C++ language standard says in D.5
2 Every C header, each of which has a name of the form name.h, behaves
as if each name placed in the standard library namespace by the
corresponding cname header is placed within the global namespace
scope. It is unspecified whether these names are first declared or
defined within namespace scope (3.3.6) of the namespace std and are
then injected into the global namespace scope by explicit
using-declarations (7.3.3).
3 [ Example: The header <cstdlib>
assuredly provides its declarations and definitions within the
namespace std. It may also provide these names within the global
namespace. The header <stdlib.h> assuredly provides the same
declarations and definitions within the global namespace, much as in
the C Standard. It may also provide these names within the namespace
std. —end example ]
This seems to state rather explicitly ("... each name ...", "...the same declarations...") that the old-style <name.h> headers must provide the same set of declarations as the new-style <cname> headers, but in global namespace. No exception is made for C++-specific overloaded versions of various C functions, for one example.
That appears to mean that <math.h> must provide three versions of sin function: sin(float), sin(double) and sin(long double) in global namespace. This, in turn, means that the following C++ code should fail overload resolution
#include <math.h>
int main() {
sin(1);
}
It does fail under MSVC++ compiler, but it compiles successfully under GCC and Clang. So, does GCC just ignore the standard requirement with regard to deprecated old-style headers? Or do I somehow misinterpret the wording in the standard?
Thanks to #hvd's comments I have seen the light, it turns out MSVC is correct and GCC should be complaining about the ambiguity as well.
The only differences between including <cmath> vs <math.h> are where the names are originally scoped, which is in namespace std for the former, and the global namespace for the latter (implementations are free to provide the names in the other namespace as well, but this isn't mandated), and the fact that including the .h variants of C headers is deprecated.

why and how does rand() exist both in global and std namespace in cstdlib?

I understand that rand(), as an example function from <cstdlib>, exists both in the global and the std namespace.
In effect the following will compile without errors, i.e. both calls to std::rand() and rand() will be legit.
#include <cstdlib>
int main() {
std::rand();
rand();
}
What is the use for this and how exactly is it implemented (the function being in both namespaces)?
The behavior is Uspecified behavior as per standard.
As per the standard including cstdlib imports the symbol names in std namespace and possibly in Global namespace. If you rely on symbol names being included in global namespace then your program is non portable and you are relying on behavior of a specific implementation.
To not rely on the implementatio behavior you must:
Include cstdlib and use fully qualified name for rand.
std::rand()
References:
C++11 Standard: D.5 C standard library headers
Para 3:
[ Example: The header <cstdlib> assuredly provides its declarations and definitions within the namespace std. It may also provide these names within the global namespace. The header <stdlib.h> assuredly provides the same declarations and definitions within the global namespace, much as in the C Standard. It may also provide these names within the namespace std. —end example ]
Good Read:
Should I include <xxxx.h> or <cxxxx> in C++ programs?
The reason is that it's originally a C function. It comes from C.
C++ re-implemented C functions like these into a std namespace. There is no difference that I know of, but it is recommended that C++ programmers use the function in the std:: namespace, first including the "c"whatever header (which is what you have indeed done with the "cstdlib" header).
(Plain C programmers would include the "stdlib.h" header, by the way.)