Can reserved function names be overloaded? - c++

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

Related

Can I extern the entire namespace?

Is there a method to declare a namespace with the extern modifier so that the namespace's entire content is externally linked?
You seem to be asking two questions. One regarding external linkage and one regarding the extern specifier.
Regarding the linkage, there is not really a need for such a syntax.
External linkage is already the default at namespace scope, whether in the global namespace or another namespace, except for const non-template non-inline variables and members of anonymous unions. (https://en.cppreference.com/w/cpp/language/storage_duration#internal_linkage)
So the other way around, syntax to make all names in a namespace have internal linkage, is more likely to be required and this is possible with unnamed namespaces
namespace {
//...
}
in which all declared names have internal linkage.
Regarding the extern specifier used to turn a variable definition into just a declaration at namespace scope or to give it external linkage explicitly, I am not aware of any syntax to apply it to a whole namespace. You will have to specify it explicitly on each variable.

Why is abs not in std?

#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]).

Does redefining a function from the standard library violate the one-definition rule?

#include <cmath>
double log(double) {return 1.0;}
int main() {
log(1.0);
}
Suppose the function log() in <cmath> is declared in global namespace (this is unspecified in fact, and we just make this assumption), then it refers to the same function as the log() function we defined.
So does this code violate the one-definition rule (see here, since no diagnostic required, this code may compile in some compiler and we cannot assert if it is correct)?
Note: After recent edits, this is not a duplicate of: What exactly is One Definition Rule in C++?
Typical scenario.
If extern "C" double log(double) is initially declared in the global namespace, then you have redeclared it and provided a definition. The implementation's previous mention of extern "C" carries over to your matching redeclaration. Your definition applies to the function belonging to the implementation, and it is an ODR violation.
As for the manifestation of UB: It's apparently common to treat log as a weak linker symbol. Your implementation overrides libc.so according to ABI rules.
(If the implementation doesn't do extern "C", it's still basically all the same.)
Other likely scenario.
If log is declared in namespace std and then brought into the global namespace, then your declaration will conflict with it. (Actually, a using declaration is technically a declaration.) This error is diagnosed.
Assumption-violating scenario.
then it refers to the same function as the log function we defined
One way for the implementation to put <cmath> names into the global namespace would be to declare extern "C" functions inside namespace std, then do using namespace std, and to ensure that this always happens as the first thing when any standard header is included. Since using namespace isn't "sticky" — it only applies to preceding declarations in the nominated namespace — the rest of the standard library would not be made visible. (This would not declare the names in the global namespace, but the standard only says "placed within the global namespace scope.")
In such an implementation, your declaration would hide the standard one and declare a new function with a new mangled name (say _Z3logd instead of simply log) and a new fully-qualified name (::log instead of ::std::log). Then there would be no ODR violation (unless some inline function uses one log in one TU and the other in a different TU).
The following addresses a previous revision of the OP. I leave it here in case future readers come here with a similar query.
I guess that two names refer to the same entity if and only if they have the same declarative region, where the concept "declarative region" is defined in the standard [...] Is this guess correct? Is there any word in the standard supporting this?
It's called variable hiding or shadowing colloquially. And the standard says what you said almost verbatim. §3.3.10 ¶1 in the current C++17 standard draft:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class
So does this code violate the one-definition rule (see here, since no diagnostic required, this code may compile in some compiler and we cannot assert it is correct)?
I won't expect it to. The standard requires that all cheader headers (and in particular cmath) introduce their symbols in the std namespace. An implementation that also pours it into the global namespace is standard conforming (since the standard leaves that bit as unspecified), but I would find in bad form. You are correct that it could happen. Now if you were to include math.h (against sage advice) then that would definitely result in a violation of the one definition rule.
Beware. The ODR only concerns definitions that will be included in the resulting program. That means that is does not concern symbols that could be present in libraries, because a (normal) linker does not load the whole libraries, but only the parts that are required to resolve symbols. For example in this code:
#include <cmath>
double log(double) {return 1.0;}
int main()
{
log(1.0);
}
There is no violation of the ODR:
either the log symbol from the C standard library was only included in the std namespace and there is no collision at all
or it is also included in global namespace
In latter case, the declaration double log(double) does not conflict with the one from cmath because it is the same. And as the symbol log is already defined, its definition from the standard library will not be included in the program. As such, only one definition for the log function exists in the program, that one: double log(double) {return 1.0;}.
Things would be different if you extracted the object module containing log from the math library and explicitely link it in your program. Because object modules are always included in the resulting program whereas object modules in libraries are only conditionaly included if they resolve undefined symbols.
References from standard:
Draft n3337 for C++11 or n4296 for C++14 (or n4618 for last revision) are explicit in paragraph 2.2 Phases of translation [lex.phases]:
§9. All external entity references are resolved. Library components are linked to satisfy external references
to entities not defined in the current translation. All such translator output is collected into a program
image which contains information needed for execution in its execution environment.
As shown code uses only one translation unit and as log is already defined in it, the definition from the library will not be used.

is it valid to use standard library function name as identifier in C++?

Consider following program:
#include <cstdio>
int main()
{
int printf=9;
std::printf("%d",printf);
}
Is it fine to use built in function name as an identifier in variable declaration? Is this well defined program? I mean is behaviour of above program well defined? I am curious to know whether the C++ standard allows to use standard function names as identifiers of variables
It's well-formed because neither std::printf nor ::printf (which may also have been declared by <cstdio>!) are declared in the same scope as your integer, which therefore takes automatic precedence for the duration of the block.
[C++14: 3.3.1/1]: [..] To determine the scope of a declaration, it is sometimes convenient to refer to the potential scope of a declaration. The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name. In that case, the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.
For example, you generally wouldn't be able to do this at namespace scope.
It's well-defined because the names of entities in the standard library are not inherently reserved names:
[C++14: 2.11/3]: In addition, some identifiers are reserved for use by C++ implementations and standard libraries (17.6.4.3.2) and shall not be used otherwise; no diagnostic is required.
[C++14: 17.6.4.3.2/1]: Certain sets of names and function signatures are always reserved to the implementation:
Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use.
Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
Yes, this is well defined behavior. You are creating an int named printf, and there is nothing currently named printf in your scope. There is something named printf in the standard scope and possibly in the global scope, but the int printf defined in local scope automatically takes precedence.
It is technically allowed to do this. There are names that are reserved in the global namespace, but inside a function, your variable name won't be visible outside the function anyway, so not a problem.
It is a terrible idea to use this.
And beware that there CAN BE problems with this approach. For example:
#define NULL 0
int main()
{
int NULL = 42;
printf("%d", NULL);
}
is not allowed, since NULL is a macro, and not a scoped identifier.
Edit: I would add that printf is not a "built in function". It is a "C standard library function". A bultin function is something like __builtin_sin, which the compiler "knows about" so that it can be optimised. Note that builtin functions typically use "reserved names", to avoid colliding with existing library and user-defined names at all times.
Relative to the identifiers in the standard libraries then the C++ Standard states only the following restruction for identifiers
3 In addition, some identifiers are reserved for use by C++
implementations and standard libraries (17.6.4.3.2) and shall not be
used otherwise; no diagnostic is required.
And (17.6.4.3.2 Global names)
1 Certain sets of names and function signatures are always reserved to
the implementation:
— Each name that contains a double underscore _ _ or begins with an
underscore followed by an uppercase letter (2.12) is reserved to the
implementation for any use.
— Each name that begins with an underscore is reserved to the
implementation for use as a name in the global namespace.
So you may use identifiers that coincide with standard function names.
On the other hand this can confuse readers of the code and lead to ambiguity.
Take into account that the Standard allows compilers to place standard C function names in the global namespace.
It is OK to do so. Because the variable int printf you defined do not belong to the namespace std as printf, which is defined in cstdio. So there is actually no conflict in names of your program.
However, if you declare
using namespace std;
before your program, and no std:: used later in your program, then it'll cause problems if you're not careful. Generally, when there is name conflicts, compiler will use the name defined in smallest scope. So if you have program like:
#include<cstdio>
using namespace std;
int main()
{
int printf = 42;
printf("%d", printf);
}
The compiler will return
error: ‘printf’ cannot be used as a function
This is because in this program, printf is defined as a int in function scope, and as a function int printf( const char* format, ... ) in global scope. Since function scope is smaller than global scope, in function int main(), printf is intepreted as int rather than function. int is not callable, hence the error message.

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.