4

Today, I was trying to answer this post (regarding checking whether a triangle can be constructed), when I encountered a weird result.

With the test of 15.15 35.77 129.07, this piece of code:

#include <iostream>
using namespace std;

const double e = 0.000001;

void f(double a, double b, double c)
{
    if (abs(180 - (a+b+c)) > e) {cout << "test"; }
}

int main()
{
    double a,b,c; cin >> a >> b >> c;
    f(a,b,c);
}

prints test as normal, while this:

#include <iostream>
const double e = 0.000001;

void f(double a, double b, double c)
{
    if (abs(180 - (a+b+c)) > e) {std::cout << "test"; }
}

int main()
{
    double a,b,c; std::cin >> a >> b >> c;
    f(a,b,c);
}

does not. The only difference is the using namespace std; line (and when I added using namespace std; to the second piece of code, as expected, it ran normally).

I've read a lot of post regarding using namespace std; over time:

but it seems that the only things using namespace std; do is cut some corners, in exchange of occasional conflicts of name of classes/variables/namespaces (the point that is brought up most when debating about whether to use it).

I did find 1 relevant post : Why does g++ (4.6 and 4.7) promote the result of this division to a double? Can I stop it? , but I didn't find anymore info elsewhere.

So what I'm I missing here?

-- Some machine info:

  • Windows 10, 64 bit
  • Code::Blocks 20.03
  • gcc/g++ 6.3.0
silverfox
  • 1,568
  • 10
  • 27
  • 2
    FWIW, your code has undefined behavior. `abs` does not live in ``, and you havent included the header you want `abs` from. Most likely you are pulling in different functions, or maybe even a macro vs a function. – NathanOliver Jun 25 '21 at 15:17
  • Have some warnings for case (2) - live - https://godbolt.org/z/W4c81ssb7 this should explain – Richard Critten Jun 25 '21 at 15:19
  • 1
    Second example wouldn't compile on my machine, missing `abs`. I added `#include ` and changed `abs` to `std::abs`. It printed `test`. – Eljay Jun 25 '21 at 15:19
  • @Eljay You've got a better implementation that OP's. Ideally, I'd want my C++ headers not to polute the global namespace as OP's does. But there's sadly no requirements on C++ implementation to. – YSC Jun 25 '21 at 15:23
  • @YSC • I use my own non-polluting headers. They work great for compiling. Not so good for linking (...like, not at all). Helps me find mistakes in implied header dependencies. – Eljay Jun 25 '21 at 15:24
  • @Eljay nice! A github repo to share with us maybe? – YSC Jun 25 '21 at 15:25
  • 1
    @YSC • Not ready for primetime yet because they're incomplete (about 50% of the standard C++ headers). Haven't shared on github. I call my project *deader files* because they're just stubs without much in the way of implementation. `constexpr` is messing me up, too, since they're not compile time evaluation friendly. They're only for C++14, because that's what I'm currently working in (not by choice, I'd rather move to C++17 for now, and C++20 ASAP... but my project is stuck in C++14). – Eljay Jun 25 '21 at 15:30
  • 1
    It is often a good idea to avoid user input in example code. Given the accepted answer, I take it you did not try replacing `double a,b,c; std::cin >> a >> b >> c;` with `double a = 15.15, b = 35.77, c = 129.07;`? Not only would that have made it easier to reproduce your result, but also it would eliminate one spot where `namespace std` comes into play. – JaMiT Jun 25 '21 at 15:43
  • @JaMiT yes, I'll take notice of that. Thanks for the suggestion! – silverfox Jun 25 '21 at 16:02

2 Answers2

7

You do have a name conflict: int abs(int) versus double std::abs(double).

With using namespace std;, abs(180 - (a+b+c)) finds both and std::abs is a better match.

Without using namespace std;, abs(180 - (a+b+c)) only finds the former and a conversion to int is necessary, hence the observed behaviour.

What you really want is:

#include <iostream>
const double e = 0.000001;

void f(double a, double b, double c)
{
    if (std::abs(180 - (a+b+c)) > e) {std::cout << "test"; }
}

int main()
{
    double a,b,c; std::cin >> a >> b >> c;
    f(a,b,c);
}
YSC
  • 38,212
  • 9
  • 96
  • 149
  • 2
    Note that you can also use `std::fabs` to explicitly document your intention NOT to use the integer version. – YSC Jun 25 '21 at 15:21
  • Ahh, I see. So the post I found did have some right on this case. I was really confused for a while now. – silverfox Jun 25 '21 at 15:21
1

That's because you haven't added std:: to abs(), thus compiler doesn't really know what function it is, ergo UB. It most likely has found and used C version of function, which is made for int arguments.

Jorengarenar
  • 2,705
  • 5
  • 23
  • 60