Yet another take on "using namespace std;"

Pages: 12
So, I've dutifully not (for once) coded "using namespace std;" and I've dutifully (for once) stuck "std::" in front of a standard library routine so as not to have an accidental name clash with one of my own functions.

So, which square root function will run from main() and why?

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <cmath>

double sqrt( double x )
{
   std::cout << "Go away, I'm gonna run my own function on " << x << " if I want to!  ";
   return -999999;
}

int main()
{
   std::cout << "The square root of 4 is ... " << std::sqrt( 4.0 ) << '\n';
}


(If your compiler complains then you can make the function definition
double sqrt( double x ) throw()
It doesn't change the outcome.)
Last edited on
Strange. My implementation has std::sqrt(float) and std::sqrt(long double), but not std::sqrt(double). Does anyone know which overloads are required by the standard? I'm wondering if it counts as an implementation bug.
Technically the result is unspecified; see https://timsong-cpp.github.io/cppwp/n4659/headers#4
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.

It so happens that the implementation(s) you've tried it on have <cmath> work as if:
1
2
3
4
#include <math.h>
namespace std {
  using sqrt = ::sqrt;
}

...which of course explicit, proper use of std:: qualifiers won't save you from, since you've just provided a definition of ::sqrt that matches the declaration provided in <math.h>.
Last edited on
So, simply prepending std:: won't save me from name clashes - I would explicitly have to put my own functions in their own namespaces? That is almost never done in this forum (although I suspect it would be done at work).

I tried it on quite a few implentations ... all with the same result.

The issue arose from a std::sin() function used in a different thread.
Last edited on
I had to follow down several layers of includes to get to the declaration of sqrt(long double). This and the overloads seem to be declared globally and then injected into the std:: namespace, so I assume the complier is just matching the definition provided with the declaration (global via the std:: injection).

I believe the standard say something about "It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std."

Does anyone know which overloads are required by the standard?

It looks like C++11 requires 4 overloads:

double sqrt(double x);
float sqrt(float x);
long double sqrt(long double x);
double sqrt(T x); // For integral type

https://www.programiz.com/cpp-programming/library-function/cmath/sqrt
Well for the original code, it uses the local def of sqrt() on VS. With VS, AFAIK the c-library functions are defined in :: if <xxx.h> is used and in :: and std:: if <cxxx> is used (pointing to the same :: function). In this case the local function 'overrides' the :: one which is the one used by std:: - hence std::sqrt() in this case calls the local version.

If you don't want the local version to be used but the std:: (or standard ::) one, then you need to put your function in a namespace. Then :: or std:: will call the standard library version and to use your own, you need to call the one in the namespace.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <cmath>

//namespace qqq {
	double sqrt(double x)
	{
		std::cout << "Go away, I'm gonna run my own function on " << x << " if I want to!  ";
		return -999999;
	}
//}

int main()
{
	std::cout << "The square root of 4 is ..." << std::sqrt(4.0) << '\n';
}


Calls the local one:


The square root of 4 is ...Go away, I'm gonna run my own function on 4 if I want to!  -999999


but by using a namespace for the local one, it calls the c-library version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <cmath>

namespace qqq {
	double sqrt(double x)
	{
		std::cout << "Go away, I'm gonna run my own function on " << x << " if I want to!  ";
		return -999999;
	}
}

int main()
{
	std::cout << "The square root of 4 is ..." << std::sqrt(4.0) << '\n';
}



The square root of 4 is ...2

I totally agree, @seeplus!

However, putting one's own functions in their own namespace doesn't get done in this forum. The advice is just "prepend std:: and all will be well".
I seem to remember this coming up a few times in the past...but what can you do? other than here are some good practices but be careful of the odd little bits of the standard that that may trip you up.
People overloading sqrt/sin also doesn't normally come up in this forum. What you demonstrated is going to be a problem regardless of "using namespace std" when dealing with most C library functions. I'll usually just tell beginners to not put it in a header file; don't care when people use it in individual files.

Perhaps a sentence could be added to https://isocpp.org/wiki/faq/coding-standards#using-namespace-std to say "use your own custom namespaces to prevent function overload ambiguities".
People overloading sqrt/sin also doesn't normally come up in this forum.
No, the ones that get you are the less commonly used things that you forgot was in the giant namespace.
eg, if you were dealing with your own class that handled currency, and had a member money, and like a good code monkey you put in your getters and setters... oops
https://en.cppreference.com/w/cpp/io/manip/get_money
For me VS2019 spits out two errors with the original code:

line 5, "C2169 'sqrt': intrinsic function, cannot be defined"
line 12, "C2264 'sqrt': error in function definition or declaration; function not called"

Remove/comment out the <cmath> header and the errors still barf up. <iostream> includes other headers?

Enclose the custom sqrt function in a custom namespace and VS2019 has no complaint. Even without <cmath> std::sqrt is called.

Curiouser and curiouser....
visual studio is notorious for that. It frequently seems to be able to find things you did not include anywhere, and when you move the code to another compiler the stuff you left off stops working. Its actually better than it was in vs 2008 / vs.net original era and earlier, but they have not completely eradicated the magic.
The original code compiles just fine using Code::Blocks with MinGW-W64 8.1.0. Calling std::sqrt calls the custom function.

Custom namespace for custom function and the C sqrt is called.

Really curiouser and curiouser.
Furry Guy wrote:
For me VS2019 spits out two errors with the original code:

line 5, "C2169 'sqrt': intrinsic function, cannot be defined"
line 12, "C2264 'sqrt': error in function definition or declaration; function not called"


hmm, my VS2019 just gives a warning (C28251: Inconsistent annotation for function: this instance has an error) on the original code. 🤷‍♂️

Edit: Release gives me the errors...
Last edited on
I normally don't compile code samples like this in debug mode, only release. Lazy, I guess. I never thought to try debug mode. *shrug*

Interesting VS2019 has "relaxed standards" with debug mode vs. release mode.

Maybe I should start using both modes. This example code shows there can be very different results.
Last edited on
With VS2019, release, warning level 4, x64, I get no errors/warnings!

But intellisense suggests warning C28251 for the sqrt function definition.

C28251: Inconsistent annotation for 'sqrt'. This instance has no annotations.

I'd forget that debug settings default to not allowing intrinsic functions and release defaults to allows them.
Inconsistent annotation for function

Oh, ICK! More SAL in the CRT with MS.

sqrt(double) definition in corecrt_math.h:
_Check_return_ _CRT_JIT_INTRINSIC double __cdecl sqrt(_In_ double _X);

About an intrinsic function with VS...

If a function is an intrinsic, the code for that function is usually inserted inline, avoiding the overhead of a function call and allowing highly efficient machine instructions to be emitted for that function.

https://docs.microsoft.com/en-us/cpp/intrinsics/compiler-intrinsics?view=msvc-160

Learn something new everyday. :)
Whether it is a standard header or not, it is reasonable to expect that the programmer who #includes a header is expected to be aware of the names (at least the global names) that are (could be) brought in by that header. This does not solve all problems when we switch to a new revision of the standard if it does introduces additional names which are also visible in the global namespace.
Pages: 12