12

If I write a new function that has the signature of a C library function, I expect a compile error due to the ambiguity. But, I can't understand why there is no error in the following C++ code.

#include <iostream>
#include <cmath>
using namespace std;

double sqrt(double number)
{
    return number * 2;  
}

int main( )
{
    cout << sqrt(2.3) << endl;
    cout << ::sqrt(2.3) << endl;
    cout << std::sqrt(2.3) << endl;
    return 0;
}

If I change the return type of sqrt() to int, then a compile error occurs due to the declaration ambiguity with double sqrt() in cmath. How is it possible to override double sqrt()? (Actually, all the cmath functions can be overridden, and I don't know why.)

Boann
  • 48,794
  • 16
  • 117
  • 146
austin
  • 131
  • 4
  • Maybe works because you declare your own function in a way that is compatible with the global declaration? ***Or*** (and much more likely) it differs enough to create a brand new overload? – Some programmer dude Oct 28 '19 at 16:38
  • 7
    What is really driving my crazy is `std::sqrt(2.3)` is calling your function as well. Why do you do this to me C++??? – NathanOliver Oct 28 '19 at 16:41
  • @NathanOliver It's not really C++ doing this to you. It's C. See that `c` letter in `#include `? – n. m. could be an AI Oct 28 '19 at 16:51
  • @n.m. But it's C++ fault for inheriting from C ;) – NathanOliver Oct 28 '19 at 16:52
  • Function argument types are part of the functions' signature, *the return type is not*. As such, defining `int sqrt(double)` has the same signature as the declaration within the standard header, but conflicts with it due to the return type. On the other hand, `double sqrt(int)` would pass without complaint because: The signature is different from the declaration within the header, so it simply adds an overload for integer arguments. – cmaster - reinstate monica Oct 28 '19 at 16:56
  • 2
    @NathanOliver Well, n.m.'s answer points out that this is UB, so the compiler is allowed to do bullshit with `std::sqrt()`... I guess that's because `std::sqrt()` is nothing but a namespace wrapper for the C function `sqrt()` which has `extern "C"` linkage. – cmaster - reinstate monica Oct 28 '19 at 16:57
  • 3
    Do not try to reason or rationalize an undefined behavior . – Omarito Oct 28 '19 at 16:58
  • Also, do not taunt Happy Fun Ball. – Robert Columbia Oct 28 '19 at 16:58
  • @NathanOliver The names in cmath will be in both global and std namespace. I wanted to show that my new sqrt() replaces the cmath sqrt() in both namespaces. – austin Oct 28 '19 at 17:04
  • @NathanOliver C++ only has that much manpower. Either inheritit from C this way, or don't have it at all. A no-brainer. – n. m. could be an AI Oct 28 '19 at 17:06

1 Answers1

11

The program has undefined behaviour.

[reserved.names]
1 The C++ standard library reserves the following kinds of names:
1.1) — macros
1.2) — global names
1.3) — names with external linkage
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.

[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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • It is mostly the equivalent of ODR violation of standard functions. – Jarod42 Oct 28 '19 at 17:06
  • The above code doesn't try to declare a function in a context where it is reserved, i.e. does not try to declare it IN the std namespace. I would say in the context of this program, the declaration is just hiding the std one. However, this view does not explain @NathanOliver point about explicitly writing std::sqrt – WilliamClements Oct 28 '19 at 17:10
  • @WilliamClements this name is reserved as a global name, not only in std namespace. – n. m. could be an AI Oct 28 '19 at 17:13
  • @n.m. Why do you think only double sqrt() shows the UB, while int sqrt() doesn't? (int sqrt gives a compile error.) – austin Oct 28 '19 at 17:16
  • @WilliamClements Well, it does declare `sqrt()` within the global namespace, for which that name is reserved as the last paragraph of the cited text indicates. Ergo, UB. – cmaster - reinstate monica Oct 28 '19 at 17:17
  • @austin Both have UB. In one case you get a compiler warning, in the other unexpected behavior. Both are valid implementations of UB. What you get is entirely down to the whims of the compiler. – cmaster - reinstate monica Oct 28 '19 at 17:19
  • @austin It's a logical fallacy. You cannot deduce that a program has no UB by observing its behaviour and noticing that it does what you expect it to do. – n. m. could be an AI Oct 28 '19 at 17:20