2

Consider the following code block:

void foo(){
  int a = div(1,2);
}

This normally will not compile, as the div function has not been declared. However, if I preceed the code with #include <map>, the code compiles. Why is map pulling in identifiers into the global namespace, and why the div function in particular? Is there a way to avoid this?

[mcve]

#include <map>

void foo(){
  int a = div(1,2);
}

int main()
{
  foo();    
}

live link - https://godbolt.org/z/Ye8rv4MTc

clang - <source>:4:7: error: no viable conversion from 'div_t' to 'int'

gcc - <source>:4:11: error: 'div' was not declared in this scope

MSVC - <source>(4): error C2440: 'initializing': cannot convert from 'div_t' to 'int'

Richard Critten
  • 2,138
  • 3
  • 13
  • 16
jhourback
  • 4,381
  • 4
  • 26
  • 31
  • 8
    Because headers may include other headers. Don't rely on this. It's implementation specific. Re the global namespace are you `using namespace std;` ? Please post a [mcve] not a code snippet ie something I can paste into my or an online compiler and duplicate the problem. – Richard Critten Jul 12 '22 at 13:20
  • Maybe so, but is there a way to avoid it? I use a `div` function elsewhere in my project, and it is confusing to have it pulled in from the standard library as well. – jhourback Jul 12 '22 at 13:22
  • Be clear about using `std::` functions or not! – πάντα ῥεῖ Jul 12 '22 at 13:22
  • I do not have a `using namespace std`. And surely `map` from the STL does not have that line. So I don't think this is related to the question regarding `using namespace std`. – jhourback Jul 12 '22 at 13:23
  • 1
    @jhourback well, then give us all the context, in form of a [mcve]!! – πάντα ῥεῖ Jul 12 '22 at 13:24
  • 1
    Update: 2 compilers think `div` is in the global namespace 1 does not - live - https://godbolt.org/z/G4hPWKPbM – Richard Critten Jul 12 '22 at 13:25
  • Do you include ``, which declares the C [`div`](https://en.cppreference.com/w/c/numeric/math/div) function? We really need a [mre] to be able to help you understand what's going on. – Some programmer dude Jul 12 '22 at 13:29
  • @Someprogrammerdude see my link above to Compiler Explorer only needs`` – Richard Critten Jul 12 '22 at 13:30
  • @RichardCritten Then it seems `` (and not ``) is included. Which I would consider to be a bug, – Some programmer dude Jul 12 '22 at 13:32
  • 1
    Reproduces on msvc too, replace `int` with `auto`... `auto a = div(1, 2);` And it too points to stdlib.h (intriguing) – Pepijn Kramer Jul 12 '22 at 13:32
  • @jhourback -- re: "I use a `div` function elsewhere in my project" -- put it in your own namespace. The global namespace is a monstrosity, and best avoided. That's why namespaces were invented. – Pete Becker Jul 12 '22 at 13:53
  • @pete-becker -- I do have it in my own namespace. But I call it within that same namespace. So just `div` is valid but confusing because there are two identifiers due to this issue. (In practice, my `div` seems to override the one from `stdlib.h`. – jhourback Jul 12 '22 at 14:37
  • @jhourback -- I don't see how that's confusing. You have it in your own namespace and that's the one that's called. That's how it's supposed to work. Yes, there may well be other definitions of the same name in other namespaces (named, unnamed, global); that's why namespaces exist. – Pete Becker Jul 12 '22 at 15:46

2 Answers2

9

Any C++ standard library header is allowed to include any other C++ standard library header.

One of these headers is <cstdlib>, which is the C++ version of the <stdlib.h> C standard library header, which declares the function div_t div(int, int).

The C++ versions of the C standard library headers generally declare all entities in the std namespace. However the standard gives implementations permission to let them declare the entities in the global namespace first and then import them into the std namespace via using declarations.

Therefore, if you include any C++ standard library header at all you must expect that any entity from the C standard library may be declared in the global namespace. div_t div(int, int) is one of these.

All of this is however unspecified behavior. There is no guarantee that div_t div(int, int) will be declared (in either the global namespace or std) if you only include <map>.

If the name conflicts with some entity you want to declare yourself, the solution is to put all of your own stuff (except main) into your own namespace. This way name lookup will prefer your declaration inside the namespace to the one outside of it in the global namespace. This should anyways always be done. There are many potential pitfalls in the global namespace in particular as there are many additional reserved identifiers, names, signatures and so on in it.

user17732522
  • 53,019
  • 2
  • 56
  • 105
0

Not an answer, but include information for msvc, so it seems it is indeed being pulled in into the global namesapce

1>main.cpp
1>Note: including file: ...\VC\Tools\MSVC\14.32.31326\include\map
1>Note: including file:  ...\VC\Tools\MSVC\14.32.31326\include\tuple
1>Note: including file:   ...\VC\Tools\MSVC\14.32.31326\include\compare
1>Note: including file:    ...\VC\Tools\MSVC\14.32.31326\include\bit
1>Note: including file:      ...\VC\Tools\MSVC\14.32.31326\include\xstddef
1>Note: including file:       ...\VC\Tools\MSVC\14.32.31326\include\cstdlib
1>Note: including file:        C:\Program Files (x86)\Windows Kits\10\Include\10.0.20348.0\ucrt\stdlib.h
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19