5

I have a vague idea of what's going on here... and it has to do with this but I'm wondering why clang++ and g++ handle this differently. Where is the undefined behaviour arround here? Note: this has nothing to do with templates - I just use them to make the example more compact. It's all about the type of whatever.

#include <iostream>
#include <vector>

template <typename T>
void test()
{
    T whatever = 'c';


    const char a = 'a';

    std::cout << "begin: " << (void*)&a << std::endl;

    const char & me = (true ? a : whatever);

    std::cout << "ref:   " << (void*)&me << std::endl;
}

int main(int argc, char**argv)
{

    test<const char>();
    test<char>();

    return 0;
}

gcc output (tested up to 4.9.3):

begin: 0x7fffe504201f
ref:   0x7fffe504201f
begin: 0x7fffe504201e
ref:   0x7fffe504201f

clang 3.7.0 output:

begin: 0x7ffed7b6bb97
ref:   0x7ffed7b6bb97
begin: 0x7ffed7b6bb97
ref:   0x7ffed7b6bb97
Community
  • 1
  • 1
neverlastn
  • 2,164
  • 16
  • 23
  • Probably reducable to `char a; const char b; const char& r = (true?a:b); std::cout << (&a==&r);` – Mooing Duck Oct 20 '16 at 17:38
  • Reproduced on gcc 4.9.2, failed to on 5.3.0 and 6.1 – krzaq Oct 20 '16 at 17:39
  • Failed to reproduce on gcc 6.2.1. – Rakete1111 Oct 20 '16 at 17:41
  • @Mooing Duck , correct. Updated answer – neverlastn Oct 20 '16 at 17:41
  • @neverlastn so where is the undefined behavior now? – space_voyager Oct 20 '16 at 17:48
  • 1
    This isn't the problem, but don't use `std::endl` unless you need the extra stuff that it does. `'\n'` ends a line. – Pete Becker Oct 20 '16 at 17:57
  • why do you think there is undefined behaviour? – Slava Oct 20 '16 at 18:12
  • Looks like gcc 4.9.2 generates temporary of type `char` from `a` to create common type with the third argument. This seem to be incorrect, but I do not see undefined behavior here. – Slava Oct 20 '16 at 18:16
  • So it's a gcc bug, not an undefined behaviour, right? Someone also told me that gcc's behaviour is OK for C++03 but not in C++11 because the spec changed in between – neverlastn Oct 20 '16 at 18:31
  • @neverlastn even if it is a bug you should not notice the difference unless you do something ugly. – Slava Oct 21 '16 at 01:10
  • @Slava - I have some innocent-looking but potentially dangerous examples [here](http://stackoverflow.com/questions/40167231/is-it-safe-to-create-a-const-reference-to-result-of-ternary-operator-in-c). – neverlastn Oct 21 '16 at 02:05
  • I recommend staying away from the gcc 4.9.x series. It has a lot of problems including very spotty c++11 support and some versions can generate bad asm. Also, be wary of people who work on gcc giving biased opinions on the matter. – xaxxon Oct 21 '16 at 04:29

1 Answers1

0

My answer from this other question from today covers your cases in detail. I'll avoid repeating myself and just summarize.

If we factor out the templates you have two cases. Case 1:

const char whatever = 'c';
const char a = 'a';
const char & me = (true ? a : whatever);

The second and third operands of the conditional operator are both "lvalue of type const char", so the result is "lvalue of type const char" designating the selected operand. Finally, const char & binds directly to "lvalue of type const char", so &me == &a.

For case 2:

char whatever = 'c';
const char a = 'a';
const char & me = (true ? a : whatever);

The second and third operand are "lvalue of type char" and "lvalue of type const char". The result of this is "lvalue of type const char" designating the selected operand. As before, const char &me binds directly to an lvalue of type const char, so &me == &a.

If a compiler prints different addresses for me and a in either case, it is a compiler bug.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365