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.
Related
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).
#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]).
As far as I understand it C-entities used by C++ like those in <math.h> can be included in a safe way inside an std namespace by including their corresponding <c...> variant (except macros, obviously). cppreference seems to confirm this.
However, including <cmath> appears to pull in the log function outside the std namespace:
#include <cmath>
namespace log {}
int main() {}
Compiled with g++ -Wall -Wextra -pedantic -std=c++17 a.cpp yields:
a.cpp:3:11: error: ‘namespace log { }’ redeclared as different kind of entity
3 | namespace log {}
| ^~~
In file included from /usr/include/features.h:446,
from /usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h:39,
from /usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h:524,
from /usr/include/c++/9/cmath:41,
from a.cpp:1:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:104:1: note: previous declaration ‘double log(double)’
104 | __MATHCALL_VEC (log,, (_Mdouble_ __x));
| ^~~~~~~~~~~~~~
Is my standard library broken? Can I do something to avoid this?
I originally stumbled over this using <random>, which means that more headers might be affected by apparently random C-entities being spewed all across the top level namespace.
Why does <cmath> expose entities outside the std namespace?
Because of history.
<cmath> header is a header inherited from the C standard library (where it is named <math.h>). In the C language, there is only the global namespace1 where all names are declared.
Since many C++ implementations are also C implementations, they often implement the inherited C standard header by including it as-is2 which means that it declares global names.
While there may be techniques to avoid (except in case of standard macros) declaring global names, it is unlikely that implementations that have been doing it since before standardisation would change the behaviour because that would break backward compatibility.
Is my standard library broken?
No. C++ standard allows this; All C standard library names are reserved for this (or any) use by the language implementation. You may not define them yourself.
Can I do something to avoid this?
You generally cannot prevent a standard library doing this.
You can technically avoid most of it by choosing to use a freestanding language implementation. But you'll lose nearly the entire standard library if you choose that.
You can minimise chances of name clashes by avoiding declaration of any global names yourself, except for a single namespace with sufficiently unique name. Something like:
namespace usr_bitmask::log {
}
1 Note that the concept of "name space" in the C language is something else.
2 And additionally, re-declares the names in the std namespace when using the <c... named header, as well as adds C++ specific overloads in some cases.
Maybe someone with more C/C++ Standard knowledge will prove me wrong, but for a C++ compiler to also being able to process C-Code, functions from the C-Library need to be outside of namespaces, in fact you should just find the C-Library definitions enclosed in a extern "C", so you can use the old C functions inside you C++ code transparently
How come this piece of code doesn't need std namespace.
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
Because you included a C header, not a C++ header.
[library.c/1]: The C++ standard library also makes available the facilities of the C standard library, suitably adjusted to ensure static type safety.
[depr.c.headers.other/1]: Every C header other than <complex.h>, <iso646.h>, <stdalign.h>, <stdbool.h>, and <tgmath.h>, 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, except for the functions described in [sf.cmath], the declaration of std::byte ([cstddef.syn]), and the functions and function templates described in [support.types.byteops]. [..] It is unspecified whether these names are first declared or defined within namespace scope ([basic.scope.namespace]) of the namespace std and are then injected into the global namespace scope by explicit using-declarations ([namespace.udecl]).
The last bolded part above says that you may have been able to use std::printf as well, but that there is no guarantee of that.
Also note that the header is deprecated:
[diff.mods.to.headers/1]: For compatibility with the C standard library, the C++ standard library provides the C headers enumerated in [depr.c.headers], but their use is deprecated in C++.
On the flip side of the coin, if you'd included cstdio instead, you'd be guaranteed to get std::printf but the availability of ::printf (the fully-qualified name of the global symbol you used) would not be guaranteed:
[headers/4]: 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 [language.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]).
Short version:
C headers like stdio.h are in the global namespace, and possibly also in std;
C++ headers like cstdio are in the namespace std, and possibly also in the global namespace.
You only need using namespace std or std:: when you're using the namespace std,
The stdio.h header file allows you to use additional methods in the standard library that do not exist in all C++ code by default. By adding the line #include , you are instructing the compiler to copy the declarations in that header file into your code so you have access to them.
The line using namespace std allows you to utilize methods in the standard namespace without having to call out the standard name space each time. This helps eliminate typos, but could introduce other errors (if two namespaces have the same method signature).
For example,
#include <iostream>
std::cout << "Hello World!" << std::endl;
Could be written as:
#include <iostream>
using namespace std;
cout << "Hello World!" << endl;
using namespace std makes names from the standard namespace visible in your namespace.
stdio.h i a header that doesn't use its own namespace but instead puts its functions (e.g. printf) etc. in the namespace in which you include it (in your case the global namespace). Therefore you can access them directly.
Note that including headers in a namespace is not generally recommended (see first comment for an example), I only mentioned it for the sake of completeness since it might not be obvious for a beginner that the placement of the include makes a difference.
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.