From the behavior and warning, I infer that std::sqrt must be calling sqrt from the global namespace -- which causes my function to be repeatedly invoked.

It would be easy enough to work around the unwanted recursion by changing the name of my sqrt function, or by putting it inside a namespace. But I would like to understand why std::sqrt is implemented in such a way that ::sqrt is called. I thought the whole point of the std namespace was to prevent name clashes with unqualified names in user code.

I took a peek at the source code for the GNU implementation of <cmath>. However, I lost the trail after following a few #includes in the chain. Maybe you can make more sense of it:

2 Answers
2

The problem is that the functions inherited from the C standard library like, e.g., the <cmath> functions are somewhat funny beasts: they are made to look as if they live in namespace std but really they are extern "C" functions living in the global namespace. Basically calling std::sqrt(x) effectively calls ::sqrt(x) which happens to be the function you just defined!

I haven't checked what the C++ standard says about these names in the global namespace but I'd be fairly certain that it classifies them as reserved names. That is, you'd better not define ::sqrt in any shape or form. Define the function in a suitable namespace and you'll be fine.

OK, I checked. The relevant clause is 17.3.24 [defns.reserved.function]:

reserved function

a function, specified as part of the C++ standard library, that must be defined by the implementation [ Note: If a C++ program provides a definition for any reserved function, the results are undefined. —end note ]

... and 17.6.4.3.3 [extern.names] paragraph 3 and 4:

Each name from the Standard C 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 Standard C 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.

Selected as the answer because it addresses the question of why recursion occurs. Can you also explain what was the point of taking all these names which are already reserved in the global namespace, and putting them into the std namespace as well? If it doesn't prevent name clashes, what purpose does it serve?
–
Matt FisherOct 31 '13 at 2:21

@MattFisher: The idea was that all names in the standard C++ library would be accessible via std::<name> (except for the few names which can't be in a namespace like operator new() which users typically wouldn't write). That's mostly done for consistency. I don't think anybody expected the names to avoid name clashes as it was clear that they would normally have extern "C" linkage.
–
Dietmar KühlOct 31 '13 at 2:28

Hmmm. The recursion is incidentally implementation-dependent. If I change my main method to call std::sqrt(4), compile with g++, and debug in gdb as before, it no longer calls my function at all. But with the same code change, if I compile with Visual C++ 2013 RC, the warning about stack overflow persists -- and the program "stops working" when executed. So "expect the unexpected" is definitely the rule when you redefine a reserved function.
–
Matt FisherOct 31 '13 at 2:32

17.6.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.17.6.4.3.3/3 Each name from the Standard C 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.17.6.4.3.3/4 Each function signature from the Standard C 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.

Upvoted as helpful -- and for being such a rapid answer. It does explain that I should not write such code, and should expect unexpected behavior if I do use a reserved name in this way.
–
Matt FisherOct 31 '13 at 2:13