Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bug in the C++ 2011 specifications

178 views
Skip to first unread message

jacobnavia

unread,
Aug 12, 2016, 2:57:23 AM8/12/16
to
The chief developper of clang has pointed out that this example CHANGES
BEHAVIOR between c++ 2008 and c++ 2011

#include <iostream>
struct S { int n; };
struct X { X(int) {} };
void f(void *) {
std::cerr << "Pointer!\n";
}
void f(X) {
std::cerr << "X!\n";
}
int main() {
f(S().n);
}

In c++ 2008 it will print X!, in c++ 2011 it will print Pointer!

The explanation is so complicated that not even the lead developper of
clang is sure about it. He doesn't seem to understand either that the
complexity of c++ has gotten SO OUT OF HAND that not even he understands
what he is doing.

Does anyone here have a clear explanation of what is happening?

Actually I am very pleased by this c++ behavior:

You need people to continuosly recompile old programs because the
language changes underneath your feets and needs people to recompile it
in the new language they have just created.

Yes, a NEW LANGUAGE, as the lead developer insists several times in his
talk.

Contrary to many people I find this behavior EXTREMELY USEFUL. It has
provided me with a job for the last months recompiling old c++ stuff
with the new compilers. I am surely not an expert (nobody is, not even
the lead developper of clang!) but I am starting to get used to it.

I am sure the new c++ 2014 will provide me plenty of job opportunities.

Öö Tiib

unread,
Aug 12, 2016, 4:08:57 AM8/12/16
to
On Friday, 12 August 2016 09:57:23 UTC+3, jacobnavia wrote:
> The chief developper of clang has pointed out that this example CHANGES
> BEHAVIOR between c++ 2008 and c++ 2011
>
> #include <iostream>
> struct S { int n; };
> struct X { X(int) {} };
> void f(void *) {
> std::cerr << "Pointer!\n";
> }
> void f(X) {
> std::cerr << "X!\n";
> }
> int main() {
> f(S().n);
> }
>
> In c++ 2008 it will print X!, in c++ 2011 it will print Pointer!
>
> The explanation is so complicated that not even the lead developper of
> clang is sure about it. He doesn't seem to understand either that the
> complexity of c++ has gotten SO OUT OF HAND that not even he understands
> what he is doing.
>
> Does anyone here have a clear explanation of what is happening?

I think that C++11 should also print X!. Where you took that from?

>
> Actually I am very pleased by this c++ behavior:
>
> You need people to continuosly recompile old programs because the
> language changes underneath your feets and needs people to recompile it
> in the new language they have just created.
>
> Yes, a NEW LANGUAGE, as the lead developer insists several times in his
> talk.
>
> Contrary to many people I find this behavior EXTREMELY USEFUL. It has
> provided me with a job for the last months recompiling old c++ stuff
> with the new compilers. I am surely not an expert (nobody is, not even
> the lead developper of clang!) but I am starting to get used to it.
>
> I am sure the new c++ 2014 will provide me plenty of job opportunities.

It is unfortunately very similar with C compilers. An actual behavior
(defined or undefined) will change between versions and things stop
working.

Same is with platforms. I was thinking that Windows changes between every
version too much until I had to develop some apps for platforms of Apple. :)
Windows is extremely stable platform.

So when some bigger code base is built on some newer version of compiler
(typically to achieve that it runs on some new version of platform) then
there will be some new compiling errors or warnings and some unit
tests also always break and there will be work to do.

jacobnavia

unread,
Aug 12, 2016, 5:12:07 AM8/12/16
to
Le 12/08/2016 à 10:08, Öö Tiib a écrit :
> I think that C++11 should also print X!. Where you took that from?

Chandler-Carruth
Lead developper of the "clang" compiler project. And before you write "I
think that..." can you compile that?

Thanks

Ben Bacarisse

unread,
Aug 12, 2016, 5:48:50 AM8/12/16
to
jacobnavia <ja...@jacob.remcomp.fr> writes:

> The chief developper of clang has pointed out that this example
> CHANGES BEHAVIOR between c++ 2008 and c++ 2011
>
> #include <iostream>
> struct S { int n; };
> struct X { X(int) {} };
> void f(void *) {
> std::cerr << "Pointer!\n";
> }
> void f(X) {
> std::cerr << "X!\n";
> }
> int main() {
> f(S().n);
> }

Interesting question. It seems to boil down to whether S().n is a
constexpr with value 0 (I think it is) and whether f(<constexpr with
value 0>) should call f(void *) (I have no idea!).

Both g++ and clang++ print "X!" for this variant of the code:

#include <iostream>
struct S { int n; };
struct X { X(int) {} };
void f(void *) {
std::cerr << "Pointer!\n";
}
void f(X) {
std::cerr << "X!\n";
}
int main() {
constexpr int c = 0;
f(c);
}

Should they both print "Pointer!"?

<snip>
--
Ben.

m.laba...@gmail.com

unread,
Aug 12, 2016, 6:39:53 AM8/12/16
to
Hi,

I have another results, it seems that c++11 corrects types handling:

--{beg:test}---------------------------------------------
$ cat main.cpp

#include <iostream>

int const value = VALUE;

struct X {
X(int) {}
};

void f(void *) {
std::cerr << "Pointer!\n";
}

void f(X) {
std::cerr << "X!\n";
}

int main() {
f(value);
}

$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ clang++ --version
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
Target: x86_64-pc-linux-gnu
Thread model: posix

$ g++ main.cpp -DVALUE=0 && ./a.out
Pointer!
$ g++ main.cpp -DVALUE=1 && ./a.out
X!
$ g++ main.cpp -DVALUE=0 -std=c++11 && ./a.out
X!
$ g++ main.cpp -DVALUE=1 -std=c++11 && ./a.out
X!
$ clang++ main.cpp -DVALUE=0 && ./a.out
main.cpp:19:5: warning: expression which evaluates to zero treated as a null pointer constant of type 'void *'
[-Wnon-literal-null-conversion]
f(value);
^~~~~
1 warning generated.
Pointer!
$ clang++ main.cpp -DVALUE=1 && ./a.out
X!
$ clang++ main.cpp -DVALUE=0 -std=c++11 && ./a.out
X!
$ clang++ main.cpp -DVALUE=1 -std=c++11 && ./a.out
X!
--{eof:test}---------------------------------------------

Regards

--
Maciej Labanowicz

Alf P. Steinbach

unread,
Aug 12, 2016, 6:54:31 AM8/12/16
to
On 12.08.2016 08:57, jacobnavia wrote:
> The chief developper of clang has pointed out that this example
> CHANGES BEHAVIOR between c++ 2008 and c++ 2011
>
> #include <iostream> struct S { int n; }; struct X { X(int) {} }; void
> f(void *) { std::cerr << "Pointer!\n"; } void f(X) { std::cerr <<
> "X!\n"; } int main() { f(S().n); }
>
> In c++ 2008 it will print X!, in c++ 2011 it will print Pointer!

There is no C++ 2008, but there is a C++ 2003; presumably that's what
you mean.


> The explanation is so complicated that not even the lead developper
> of clang is sure about it.

In

http://stackoverflow.com/a/23048287/464581

it's maintained that C++11 nullpointer constants have to be literals, as
opposed to C++03 constant expressions.

I can't find that in the standard (N3290 draft), so, even though that's
what I believed until now, I think it's a misunderstanding based on the
standard's term “literal type”.

But for sure there was some change.


> He doesn't seem to understand either that the complexity of c++ has
> gotten SO OUT OF HAND that not even he understands what he is doing.

Oh my.


> Does anyone here have a clear explanation of what is happening?

I think C++11 was OK but C++14 included many local kludge-like fixes and
kludge-like “improvements”. It seems to me the language is shattering
into disconnected small pieces that sometimes end up being incompatible
with each other, and anyway introduce great complexity. I think what
happened was that the people with long views who cared for a clean
language, got too old and more or less dropped out, while bright new
Asperger's syndrome good-at-memorization folks got into the act.

But maybe you're asking specifically about nullpointer constants.

I'm not sure exactly where, but the change seems to reside with the
definition of /integral constant expression/. Both C++03 and C++11
define a null pointer constant as an integral constant expression,
except that C++11 additionally allows a std::nullptr_t prvalue.


Cheers & sorry for not having more clear-cut facts,

- Alf

Richard

unread,
Aug 12, 2016, 1:00:13 PM8/12/16
to
[Please do not mail me a copy of your followup]

ja...@jacob.remcomp.fr spake the secret code
<nok3sq$dkb$1...@dont-email.me> thusly:
Chandler Carruth is the lead developer of the C++ tools team at
google. I don't think clang itself can be considered to have a
single lead developer. Different people take responsibility for
different areas. See
<https://github.com/llvm-mirror/llvm/blob/master/CODE_OWNERS.TXT>
<https://github.com/llvm-mirror/clang/blob/master/CODE_OWNERS.TXT>
<https://github.com/llvm-mirror/clang-tools-extra/blob/master/CODE_OWNERS.TXT>
etc.

Getting back to the example code, my takeaway is two-fold:

1) It's been a well known problem that overloading functions for a pointer
type and an integer type leads to surprises. Is NULL an integer or is
it a pointer? It depends on the implementation. This is one of the
reasons why nullptr/nullptr_t was added to the language. Overloading
on both of these types as the only difference in the signature is
going to be surprising unless you static_cast<> appropriately.

2) Single argument constructors that allow implicit conversion between
types is also a well known problem that leads to surprises. All the
C++ "lint" like tools I know of report warnings or errors for such
constructors and advise you to make the constructor explicit.

This code wouldn't lead to such surprising results if it had been
written to avoid these well known areas of surprise.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

woodb...@gmail.com

unread,
Aug 12, 2016, 4:20:08 PM8/12/16
to
I consider myself to have a long view of things and I had to
stay out in order to survive. If you can't join 'em, beat 'em.

Now is the time for a group of G-dly men and women to work
together to help C++.

https://groups.google.com/forum/#!searchin/comp.lang.c$2B$2B/comments$20$20%22scott$20meyers%22%7Csort:date/comp.lang.c++/5q7jqe6GPiA/NUfq1NZ1R1sJ

Brian
Ebenezer Enterprises

"The righteous will flourish like a palm tree,
they will grow like a cedar of Lebanon;
planted in the house of the L-rd,
they will flourish in the courts of our G-d.

They will still bear fruit in old age,
they will stay fresh and green,
proclaiming, “The L-rd is upright;
He is my Rock, and there is no wickedness in Him.” Psalms 92:12-15

http://webEbenezer.net

Mr Flibble

unread,
Aug 12, 2016, 4:48:53 PM8/12/16
to
Brian, fuck off.

/Flibble


woodb...@gmail.com

unread,
Aug 12, 2016, 5:43:26 PM8/12/16
to
On Friday, August 12, 2016 at 3:48:53 PM UTC-5, Mr Flibble wrote:

If you repent, Leigh, you could join the group.
C.S. Lewis said that G-d told him to, "Put down
your gun and we'll talk."

I support law abiding citizens having guns so don't
want to give the wrong idea by quoting that.
Lewis could either make peace with G-d or run away
with his gun.



jacobnavia

unread,
Aug 12, 2016, 5:49:12 PM8/12/16
to
Le 12/08/2016 à 10:08, Öö Tiib a écrit :
> It is unfortunately very similar with C compilers. An actual behavior
> (defined or undefined) will change between versions and things stop
> working.

Yes, true.

But I do not know how many orders of magnitude less than in c++, you
will agree with me.

C is VERY stable language, and software written in C stands the time
test. A C beautifier program is still running in the lcc-win IDE, code
written in the eighties.


jacobnavia

unread,
Aug 12, 2016, 5:58:14 PM8/12/16
to
Le 12/08/2016 à 23:43, woodb...@gmail.com a écrit :
> I support law abiding citizens having guns

Yes, you must live in the U.S.A. In that country, people kill themselves
with their guns for nothing. Everyone has a gun and everyone is shooting
around. A grand parent kills his grand daughter because he mistakenly
thought it was an intruder.

Mass shootings everywhere, they are the latest gun fad.

Violence is destroying the basic assumptions about society but the
shooting goes on and on.

Yes, we should fight the shooting with...

MORE GUNS.

LAW ABIDING CITIZENS do not have guns in most civilized countries.
Happily for us, we do not live near those "law abiding" citizens ready
to shoot anyone that approaches.

This sickness has contaminated the whole country and the shooting has
increased, multiplied by the media and all people like you:

> I support law abiding citizens having guns

you said.

Gun happy.


jacobnavia

unread,
Aug 12, 2016, 6:19:52 PM8/12/16
to
Le 12/08/2016 à 08:57, jacobnavia a écrit :
> The chief developper of clang has pointed out that this example CHANGES
> BEHAVIOR between c++ 2008 and c++ 2011
>
> #include <iostream>
> struct S { int n; };
> struct X { X(int) {} };
> void f(void *) {
> std::cerr << "Pointer!\n";
> }
> void f(X) {
> std::cerr << "X!\n";
> }
> int main() {
> f(S().n);
> }
>

Look I do not know c++ but anyway... I think in that language programs
start in the "main" function. We start there then.

We have a function call of an "f" function, where you have two possible
alternatives: One that receives a void * (a pointer to "anything") and
another that receives an "X", i.e. a structure that has only a
constructor. This constructor receives an int as argument.

To know what is being passed to "f" (data that will determine the one
"f" being called) we have to simply evaluate the expression:

S().n

This looks like the constructor of "S" being called to make an "S", then
using the result to acces its "n" member above.

This is the default constructor because nowhere is a constructor for "S"
in scope. And I suppose that the default constructor always initializes
ints to zero. Then, the outcome of a call to an "S" constructor in this
scope is fixed, since it is the default constructor: zero.

The type of the expression is then the integer zero, an ambiguous value
now, since can be a null pointer AND an integer. According to obscure
rules that nobody really understands, an integer is an input for the
constructor of "X" objects, and that can be used to build an "X", that
is passed to the overloaded function in scope that prints X!

I remember when I was young and naive, and started to read the rules for
operator overloading in the c++ standard. They went for pages and pages
of stuff like a topological sort of all classes in scope.

Well they ARE C++ heads, that is for sure. But now we have since a long
long time reached the level where nobody understands anything any more
and a 12 line program suffices for provoking and big embarrased silence.

Now, just out of curiosity...

Where did I go wrong?

Thanks

Alf P. Steinbach

unread,
Aug 12, 2016, 6:40:31 PM8/12/16
to
Just a technicality: `S()` is not invoking a default constructor,
because there isn't one, but is "value initialization", which reduces to
zero-initalization in this case. So the outcome is as you described,
just via a slightly different mechanism (unfortunately it does matter in
some situations, more complexity...). The difference between C++
versions appears to be that this zero value can be regarded as a compile
time integer 0, a "constant expression" 0 in C++11, but not in C++03,
which has less smarts.

IMO the same phenomenon, of too "smart" things, is going to hit us via
appliances, the internet of things, in just some years.

Watch for when your fridge is hacked by some silly teenagers who target
everyone who buys a brand of beer that they don't like, via an attack
vector provided by the extreme complexity of the fridge's OS.


Cheers!,

- Alf

David Brown

unread,
Aug 13, 2016, 11:28:36 AM8/13/16
to
Yes, that is one of C's biggest strengths, and biggest weaknesses - it
does not change (or does so only very little, and very slowly). C++, on
the other hand, /does/ change - both the language, the standard library,
and the tools. And again, that is both a strength and a weakness.

That's why it's good to have both languages, suited to different purposes.



Mr Flibble

unread,
Aug 13, 2016, 1:51:34 PM8/13/16
to
On 12/08/2016 23:40, Alf P. Steinbach wrote:
> On 13.08.2016 00:19, jacobnavia wrote:
>> Le 12/08/2016 à 08:57, jacobnavia a écrit :
>>> The chief developper of clang has pointed out that this example CHANGES
>>> BEHAVIOR between c++ 2008 and c++ 2011
>>>
>>> #include <iostream>
>>> struct S { int n; };
>>> struct X { X(int) {} };
>>> void f(void *) {
>>> std::cerr << "Pointer!\n";
>>> }
>>> void f(X) {
>>> std::cerr << "X!\n";
>>> }
>>> int main() {
>>> f(S().n);
>>> }
>>>
[snip]

> Just a technicality: `S()` is not invoking a default constructor,
> because there isn't one, but is "value initialization", which reduces to
> zero-initalization in this case. So the outcome is as you described,
> just via a slightly different mechanism (unfortunately it does matter in
> some situations, more complexity...). The difference between C++
> versions appears to be that this zero value can be regarded as a compile
> time integer 0, a "constant expression" 0 in C++11, but not in C++03,
> which has less smarts.

Wrong. C++11 will not regard it as a compile time integer; if it does
then your compiler has a bug. A C++11 compiler I just tried will output
"X!" as it should.

/Flibble

jacob navia

unread,
Aug 13, 2016, 6:44:11 PM8/13/16
to
Le 13/08/2016 à 19:51, Mr Flibble a écrit :

> Wrong. C++11 will not regard it as a compile time integer; if it does
> then your compiler has a bug. A C++11 compiler I just tried will output
> "X!" as it should.
>
> /Flibble
>

Not according to the developer in the clang team. His argument is that
const expressions take priority here, and the 2011 version changes the
behavior of the null constant since they are (apparently) propagated in
priority.

Now, since you do not name the compiler you are using I can't tell if
the fact that you see some output is because you didn't specify std-c++
2011 or not, or because other reasons.

What is interesting in this discussion is that humans can only say:

"Compiler xyz outputs this"

and nobody understands the priorities anymore... This whole stuff is so
complicated that all the human experts here are completely overwhelmed.

You say that "X" is what it "SHOULD" output the compiler but you do not
forward any explanation.

Your "explanation" is that an unknown compiler outputs something!

Is that because c++ is now only "readable" by a machine? The rules and
their unforeseen interactions can't be followed by people anymore?

I think that a reflection is needed by the users and the developer of
this language to come to their senses before c++ will be definitely
fucked up.

Sorry but that is what this is leading to. A computer language that only
a machine can fully understand. Humans are unable to parse 12 lines of
C++ and all come to the same conclusion.

In my message I tried to give A REASONING.

Starting with the main function, I spelled out the rules that I think
apply here and explained the steps one by one. If that is impossible for
you, you are just begging my question.

Where did I went wrong?

Thanks for pointing me where I erred. And stop compiling that code. It
is now the question if anyone here UNDERSTANDS what is written there and
the actions the machine should perform.

jacob

Ian Collins

unread,
Aug 13, 2016, 7:06:42 PM8/13/16
to
On 08/14/16 10:44 AM, jacob navia wrote:
> Le 13/08/2016 à 19:51, Mr Flibble a écrit :
>
>> Wrong. C++11 will not regard it as a compile time integer; if it does
>> then your compiler has a bug. A C++11 compiler I just tried will output
>> "X!" as it should.
>>
>> /Flibble
>>
>
> Not according to the developer in the clang team. His argument is that
> const expressions take priority here, and the 2011 version changes the
> behavior of the null constant since they are (apparently) propagated in
> priority.

I agree with Flibble, the output should be "X!". So do all of the
compilers on my boxes:

$ cat > x.cc
#include <iostream>
struct S { int n; };
struct X { X(int) {} };
void f(void *) {
std::cerr << "Pointer!\n";
}
void f(X) {
std::cerr << "X!\n";
}
int main() {
f(S().n);
}

clang++ -std=c++11 x.cc; ./a.out; clang++ --version
X!
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

/opt/gcc5/bin/g++ x.cc -std=c++11; ./a.out; /opt/gcc5/bin/g++ --version
X!
g++ (GCC) 5.3.1 20151213

CC x.cc -std=c++11; ./a.out; CC -V
X!
CC: Studio 12.5 Sun C++ 5.14 SunOS_i386 2016/05/31

> Starting with the main function, I spelled out the rules that I think
> apply here and explained the steps one by one. If that is impossible for
> you, you are just begging my question.
>
> Where did I went wrong?

There isn't any ambiguity, the constructor for X is the only fit.

If you change the constructor to be explicit (which it should be, no
matter what version of C++ you use), the code won't compile no matter
what version of C++ you specify.

--
Ian

jacob navia

unread,
Aug 13, 2016, 7:20:42 PM8/13/16
to
OK OK. And what happens when you put std-c++2003 or equivalent on clang?
The thing is that (according to the clang developper) the behavior CHANGED.


Ian Collins

unread,
Aug 13, 2016, 7:24:45 PM8/13/16
to
clang++ -std=c++03 x.cc; ./a.out; clang++ --version
X!
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)

--
Ian

jacob navia

unread,
Aug 13, 2016, 7:37:04 PM8/13/16
to
Le 12/08/2016 à 08:57, jacobnavia a écrit :


Please look at
https://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Clang-Defending-C-from-Murphy-s-Million-Monkeys

In that talk, see the slide and discussion. Starts around minute 47 of
the video

jacob navia

unread,
Aug 13, 2016, 7:38:52 PM8/13/16
to

Mr Flibble

unread,
Aug 13, 2016, 8:33:01 PM8/13/16
to
Easy explanation: the clang guy is simply wrong.

/Flibble

jacob navia

unread,
Aug 14, 2016, 3:10:02 AM8/14/16
to
Le 14/08/2016 à 02:32, Mr Flibble a écrit :

>>
>> See the discussion of that in
>> https://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Clang-Defending-C-from-Murphy-s-Million-Monkeys
>>
>>
>>
>> Minute 47 of the video.
>
> Easy explanation: the clang guy is simply wrong.
>

Well, if you know that he is "wrong" can you explain WHY is he wrong?

Or he is wrong because some unknown compiler you are using seems to say
otherwise?


Ian Collins

unread,
Aug 14, 2016, 3:13:04 AM8/14/16
to
We've already been over that.

--
Ian

Alf P. Steinbach

unread,
Aug 14, 2016, 8:11:15 AM8/14/16
to
No, as I see it that's a blind assertion, an incorrect one.

Jacob asks for a deduction from the official standard's rules, not
examples of particular compilers' behaviors.

And our inability to give him that tends to support his contention that
the language, or at least the standard's way of describing the language,
has become too complex.


Cheers!,

- Alf

Mr Flibble

unread,
Aug 14, 2016, 8:29:40 AM8/14/16
to
It is not an incorrect assertion. An lvalue can never be a null pointer
constant. You, like the clang guy, are simply wrong.

/Flibble

Alf P. Steinbach

unread,
Aug 14, 2016, 9:26:51 AM8/14/16
to
On 14.08.2016 14:29, Mr Flibble wrote:
>
> An lvalue can never be a null pointer constant.

Are you sure that `S().x` is an lvalue?

Let's check that assertion, using your own proof technique, what
compilers say about it:

struct S{ int x; };

auto main() -> int
{
S().x = 666;
}

<compilation>
[C:\my\temp]
> g++ foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:5:11: error: using temporary as lvalue [-fpermissive]
S().x = 666;
^

[C:\my\temp]
> cl foo.cpp
foo.cpp

[C:\my\temp]
> _
</compilation>

Oh my, they disagree!

What do you think the standard says about it?


Cheers & hth.,

- Alf

Mr Flibble

unread,
Aug 14, 2016, 9:51:12 AM8/14/16
to
On 14/08/2016 14:26, Alf P. Steinbach wrote:
> On 14.08.2016 14:29, Mr Flibble wrote:
>>
>> An lvalue can never be a null pointer constant.
>
> Are you sure that `S().x` is an lvalue?
>
> Let's check that assertion, using your own proof technique, what
> compilers say about it:
>
> struct S{ int x; };
>
> auto main() -> int

Do you realize how demented that looks? Take your meds and write:

int main()

like any sane person would.

> {
> S().x = 666;
> }
>
> <compilation>
> [C:\my\temp]
>> g++ foo.cpp
> foo.cpp: In function 'int main()':
> foo.cpp:5:11: error: using temporary as lvalue [-fpermissive]
> S().x = 666;
> ^
>
> [C:\my\temp]
>> cl foo.cpp
> foo.cpp
>
> [C:\my\temp]
>> _
> </compilation>
>
> Oh my, they disagree!

Intel's compiler also allows the assignment.

>
> What do you think the standard says about it?

According to the Standard it is an rvalue however it also has a *name*.

/Flibble

Mr Flibble

unread,
Aug 14, 2016, 9:57:40 AM8/14/16
to
leigh@server:~$ cat test.cpp
struct s
{
int n;
};

int main()
{
constexpr int z1 = 0;
const int z2 = 0;
int z3 = 0;
void* p0 = 0;
void* p1 = z1;
void* p2 = z2;
void* p3 = z3;
void* p4 = s().n;
}
leigh@server:~$ g++ -std=c++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:12:13: error: invalid conversion from ‘int’ to ‘void*’
[-fpermissive]
void* p1 = z1;
^
test.cpp:13:13: error: invalid conversion from ‘int’ to ‘void*’
[-fpermissive]
void* p2 = z2;
^
test.cpp:14:13: error: invalid conversion from ‘int’ to ‘void*’
[-fpermissive]
void* p3 = z3;
^
test.cpp:15:17: error: invalid conversion from ‘int’ to ‘void*’
[-fpermissive]
void* p4 = s().n;
^
leigh@server:~$ clang -std=c++11 test.cpp
test.cpp:12:8: error: cannot initialize a variable of type 'void *' with an
lvalue of type 'const int'
void* p1 = z1;
^ ~~
test.cpp:13:8: error: cannot initialize a variable of type 'void *' with an
lvalue of type 'const int'
void* p2 = z2;
^ ~~
test.cpp:14:8: error: cannot initialize a variable of type 'void *' with an
lvalue of type 'int'
void* p3 = z3;
^ ~~
test.cpp:15:8: error: cannot initialize a variable of type 'void *' with an
rvalue of type 'int'
void* p4 = s().n;
^ ~~~~~
4 errors generated.
leigh@server:~$

/Flibble

Rick C. Hodgin

unread,
Aug 14, 2016, 10:16:11 AM8/14/16
to
Examine the generated assembly source code in non-optimized
mode. It will show you exactly what's happening, and what
is what.

Best regards,
Rick C. Hodgin

Mr Flibble

unread,
Aug 14, 2016, 10:18:31 AM8/14/16
to
On 14/08/2016 15:16, Rick C. Hodgin wrote:
> Examine the generated assembly source code in non-optimized
> mode. It will show you exactly what's happening, and what
> is what.

There won't be any assembly because the compilation fails (as it
should). Use your brain mate.

/Flibble

Alf P. Steinbach

unread,
Aug 14, 2016, 10:36:08 AM8/14/16
to
On 14.08.2016 15:51, Mr Flibble wrote:
> On 14/08/2016 14:26, Alf P. Steinbach wrote:
>> On 14.08.2016 14:29, Mr Flibble wrote:
>>>
>>> An lvalue can never be a null pointer constant.
>>
>> Are you sure that `S().x` is an lvalue?
>>
>> Let's check that assertion, using your own proof technique, what
>> compilers say about it:
[snip]
>
> ... demented ...
>
> According to the Standard it is an rvalue

So, your assertion about lvalue turned out to be irrelevant: `S().x` is
an rvalue, not an lvalue.


> however it also has a *name*.

Uhm?

Manfred

unread,
Aug 14, 2016, 11:23:34 AM8/14/16
to
On 08/14/2016 01:06 AM, Ian Collins wrote:
> On 08/14/16 10:44 AM, jacob navia wrote:
>>
>> Where did I went wrong?
>
> There isn't any ambiguity, the constructor for X is the only fit.
Agreed: the expression S().n has type int indeed.
>
> If you change the constructor to be explicit (which it should be, no
> matter what version of C++ you use), the code won't compile no matter
> what version of C++ you specify.
>

Therefore compilers which end up with Pointer! are wrong, and since they
appear not to be irrelevant (my gcc always outputs X! by the way), this
confirms the complexity of the language, IMHO. Meaning that the original
cleanliness of the language risks to get polluted by newer "improvements"

Regards

jacob navia

unread,
Aug 14, 2016, 1:06:26 PM8/14/16
to
Le 14/08/2016 à 17:23, Manfred a écrit :
> this confirms the complexity of the language, IMHO. Meaning that the
> original cleanliness of the language risks to get polluted by newer
> "improvements"

Exactly the point I am trying to make.

Interactions between each new "feature" with old features, added to
things that were already wrong (the ambiguity between 0 as an integer
and 0 as a null pointer) that weren't fixed but now reachy new places
where they can bite the unaware.

What I want to say is this:

C++ is reaching the point where only a machine can follow the extremely
complex rule's interaction.

Programmers can't follow and when they use the language they CAN'T
foresee exactly what will happen.

The example I gave is just 12 lines of C++!

It is not the sheer size of the example, it is just that humans can't
follow the rules!

jacob

jacob navia

unread,
Aug 14, 2016, 2:58:38 PM8/14/16
to
Le 12/08/2016 à 18:59, Richard a écrit :
> [Please do not mail me a copy of your followup]
>
> ja...@jacob.remcomp.fr spake the secret code
> <nok3sq$dkb$1...@dont-email.me> thusly:
>
>> Le 12/08/2016 à 10:08, Öö Tiib a écrit :
>>> I think that C++11 should also print X!. Where you took that from?
>>
>> Chandler-Carruth
>> Lead developper of the "clang" compiler project. And before you write "I
>> think that..." can you compile that?
>
> Chandler Carruth is the lead developer of the C++ tools team at
> google. I don't think clang itself can be considered to have a
> single lead developer. Different people take responsibility for
> different areas. See
> <https://github.com/llvm-mirror/llvm/blob/master/CODE_OWNERS.TXT>
> <https://github.com/llvm-mirror/clang/blob/master/CODE_OWNERS.TXT>
> <https://github.com/llvm-mirror/clang-tools-extra/blob/master/CODE_OWNERS.TXT>
> etc.
>
> Getting back to the example code, my takeaway is two-fold:
>
> 1) It's been a well known problem that overloading functions for a pointer
> type and an integer type leads to surprises.

Yes. And what about fixing THOSE problems BEFORE adding new features?


> Is NULL an integer or is
> it a pointer?

Zero is zero, and a zero pointer points to the first available memory
location. It is useful to make this (easy to test) location a convention
for meaning:

1) This pointer has no value yet, or

2) its value was destroyed, or

3) it means "not found", when you call a search function.

> It depends on the implementation.

Maybe there are more use cases but let's keep those three use cases.
Then, the standard should give SIMPLE rules what is NULL in which context.

Problem is, that C++ has becomed plagued with ambiguity, since automatic
generated code is issued on behalf of the programmer.

This feature can be used, but also abused, it is a matter of measure.
The golden rule is that the language should be able to be parsed by a
qualified reader in a short period of time. Rules should be easy to
grasp and their number should be reduced to a minimum.

There are too many interacting constructs that come to be added to the
language, complexifying even more a complex situation. Let's STOP.

I have a solution:

Let's make the compiler itself PROGRAMMABLE. Let's design a simpler
language but with a programmable compiler where it is easy to write new
constructs without complexifying the whole language.

Conceptually then, a compiler is a source of syntactic and grammatical
EVENTS.

The automata starts in the null state, and its state is governed by the
text written in the source code.

A series of events is generated by the compiler. For instance:

Start struct declaration
End struct declaration

Constructors / Destructors belong here.

Start statement
End Statement

A profiler could subscribe to those events, and generate code to measure
the time the processor spent executing that statement

A debugger could generate code to be passed control if doing single
stepping.


Start function/method definition
End function/method definition

And many other events the compiler user can meaningfully use in the
application they are writing. Lambdas? Of course. If you need them
you use one of the language libraries around. Those libraries subscribe
to compiler events and generate code for you to do lamndas, and many
other quite interesting software constructs.

The core language stays fixed, the text is portable. Libraries are less
portable, and sophisticated software constructs have a price. But it is
again the user that decides if he wants the extra complexity of writing
and mainting that kind of code. New features are introduced individually
in some installations and people gain experience using them.

After some years of usage and if the authors want it, libraries would
enter the Boost library and become semi-official, with lambdas, regular
expressions, closures, what have you. This language libraries would hang
their code in specific events generated by the compiler and would write
either:

Core language to be compiled, inserted into the text stream at the call
point

or

Assembler to be inserted at the exact point of the event firing into the
object code stream.

Maybe more on this later

This is one of the
> reasons why nullptr/nullptr_t was added to the language. Overloading
> on both of these types as the only difference in the signature is
> going to be surprising unless you static_cast<> appropriately.
>

Of course. It is impossible for the automata to disambiguate the two
meanings since it has no notion of "meaning". It is the programmer
that gives any meaning here, and in this case it could be required.

> 2) Single argument constructors that allow implicit conversion between
> types is also a well known problem that leads to surprises. All the
> C++ "lint" like tools I know of report warnings or errors for such
> constructors and advise you to make the constructor explicit.
>
> This code wouldn't lead to such surprising results if it had been
> written to avoid these well known areas of surprise.
>

Ian Collins

unread,
Aug 14, 2016, 3:24:03 PM8/14/16
to
Which compilers are they?

--
Ian

Chris Vine

unread,
Aug 14, 2016, 4:08:56 PM8/14/16
to
Every language has its corner cases. It is a necessary consequence of
writing rules.

Your example is highly artificial. No one in their right minds would
write code of that kind for a meaningful purpose, and I am certainly not
going to spend the time reaching a view about which of the views
expressed is correct (although I thought your original appeal to
authority in the guise of "the chief developper of clang (sic)" somewhat
amusing).

You are a long standing poster to this group perennially making posts
adverse to C++. That's fine, you have your axe to grind and you are
entitled to your opinion. C is your preferred language. Stick to it.

Chris Vine

unread,
Aug 14, 2016, 4:28:28 PM8/14/16
to
On Sun, 14 Aug 2016 20:58:24 +0200
jacob navia <ja...@jacob.remcomp.fr> wr
> Let's make the compiler itself PROGRAMMABLE. Let's design a simpler
> language but with a programmable compiler where it is easy to write
> new constructs without complexifying the whole language.

There is already a language group which will do that for you, namely
the lisps. I prefer the scheme dialect, which has hygienic macros. It
is there: instead of your talking, get coding. I will trade macros with
you if you really want.

C++ is not a homoiconic language, and it is pointless complexifying it
to try to make it so. Neither for that matter is C, whose macro system
is totally pathetic. C++ has to carry the C baggage with it, for
better or for worse (mainly for worse).

jacob navia

unread,
Aug 14, 2016, 4:52:11 PM8/14/16
to
Le 14/08/2016 à 22:08, Chris Vine a écrit :

> Every language has its corner cases. It is a necessary consequence of
> writing rules.
>

True. But most language programmers can identify those corner cases and
answer a simple answer to them.

Too many rules to learn but heart provoke languages that are obese.

Obsesity is a consequence of a lack of restrain.

> Your example is highly artificial. No one in their right minds would
> write code of that kind for a meaningful purpose, and I am certainly not
> going to spend the time reaching a view about which of the views
> expressed is correct (although I thought your original appeal to
> authority in the guise of "the chief developper of clang (sic)" somewhat
> amusing).
>

Yes the whole is very amusing. I get a kick with all that for sure.

And that guy is a nobody of course. And the fact that he says (and a
user in this discussion proved) that there is a problem with the rules
it is of no importance since:

> You are a long standing poster to this group perennially making posts
> adverse to C++.

Yes, I think the complexity of that language that I have to maintain is
a horror. Fortunately it exists of course, I am not against c++ since it
as source of revenue for me.

But sometimes I post in this group because I see the whole boat go into
such extremes that is... yes, amusing. That is the right word.

That's fine, you have your axe to grind and you are
> entitled to your opinion. C is your preferred language. Stick to it.
>

Of course I will stick to it. There is no question about that. But at
work I should maintain those horrors you see?

I have to understand why that crashes now when I recompiled the code
without changing anything. Then I *have* to know c++ and I start
sometimes talks in this group.

I even try to impromve my c++ skills by looking at c++ conferences,
videos, etc. And I presented that case brought by the speaker for the
clang group in that conference. Of course he is wrong, he is a nobody,
and he is not a lead developer but a beginner saying nonsense.

In any case that guy knows MUCH MORE c++ than me

:-)

jacob

Chris Vine

unread,
Aug 14, 2016, 4:55:34 PM8/14/16
to
On Sun, 14 Aug 2016 22:52:02 +0200
jacob navia <ja...@jacob.remcomp.fr> wrote:
> [drivel snipped]

You are still missing the point. Your example is highly artificial.
No one in their right minds would write code of that kind for a
meaningful purpose, and I am certainly not going to spend the time
reaching a view about which of the views expressed is correct.

jacob navia

unread,
Aug 14, 2016, 5:08:14 PM8/14/16
to
Le 14/08/2016 à 22:55, Chris Vine a écrit :
> On Sun, 14 Aug 2016 22:52:02 +0200
> jacob navia <ja...@jacob.remcomp.fr> wrote:
>> [drivel snipped]
>
> You are still missing the point. Your example is highly artificial.


Of course not!!!!!!!

That is a condensate of a problem that will appear in a huge program
where conceptually those 12 lines are dispersed in several different
files across several classes and templates and what have you!!!!!

> No one in their right minds would write code of that kind for a
> meaningful purpose,

THAT IS A MINIMAL EXAMPLE OF THE PROBLEM MAN!

Please turn on the brain before posting!


A "minimal example" in compiler parlance, is a very small code snippet
that highlights a problem that could be dispersed in several different
locations!

> and I am certainly not going to spend the time
> reaching a view about which of the views expressed is correct.
>

Of course not. If you do not feel like not doing it do not do it!

But then just keep silent since you have nothing to say and the only
thing that you can say is that I am just speaking

"drivel"

that can be ignored, without engaging a single argument or technical point

Chris Vine

unread,
Aug 14, 2016, 5:15:36 PM8/14/16
to
On Sun, 14 Aug 2016 23:08:05 +0200
jacob navi
> THAT IS A MINIMAL EXAMPLE OF THE PROBLEM MAN!

Hot air. It isn't a problem.

I'll call you. Give me real code you might actually want to write for
a meaningful purpose where this is a live issue. Post it to a pasting
service if you think that would be better. If you could explain what
result you were expecting and why it didn't deliver it, and how it
relates to the code you posted, that would help also.

jacob navia

unread,
Aug 14, 2016, 5:17:50 PM8/14/16
to
Le 14/08/2016 à 22:28, Chris Vine a écrit :
> There is already a language group which will do that for you, namely
> the lisps. I prefer the scheme dialect, which has hygienic macros.

Macros are expanded in their position in the program text. They aren't
called automatically by the compiler system when an EVENT (syntactic or
similar) fires.

Is like the signal/slot paradigm in windows programming. You are just
not even understanding the change that means a stream of compiler EVENTS
where you can change the language by adding special syntax and ad hoc
syntax within an application context. I mentioned several examples in my
post.

To all that you have nothing to say. It suffices to say:

<quote>
C++ is not a homoiconic language, and it is pointless complexifying it
to try to make it so.
<end quote>

Then we have the situation where many constructs like lambdas, closures,
and other lisp features are added to the *whole* language instead of
being part of a LIBRARY!

There is then a monolithic compiler and an increasing unreadable
language that emerges.

The concept of language LIBRARIES where a adapted syntax and code
generation are unified in a standard context and added to some users and
tested for years without being IMPOSED to all users of the language!



Chris Vine

unread,
Aug 14, 2016, 5:42:31 PM8/14/16
to
On Sun, 14 Aug 2016 23:17:40 +0200
jacob navia <ja...@jacob.remcomp.fr> wrote:
> Le 14/08/2016 à 22:28, Chris Vine a écrit :
> > There is already a language group which will do that for you, namely
> > the lisps. I prefer the scheme dialect, which has hygienic
> > macros.
>
> Macros are expanded in their position in the program text. They
> aren't called automatically by the compiler system when an EVENT
> (syntactic or similar) fires.
>
> Is like the signal/slot paradigm in windows programming. You are just
> not even understanding the change that means a stream of compiler
> EVENTS where you can change the language by adding special syntax and
> ad hoc syntax within an application context. I mentioned several
> examples in my post.

It is still compile time computation.

I don't buy your examples at all, and I think you are just confusing
yourself.

This is not really a point about C++, even though you try to dress it
as such: it is about a new method of generating object code at compile
time. Prove me wrong: raise capital, found a start-up and make a lot of
money. Begin with C, your preferred language.

Öö Tiib

unread,
Aug 14, 2016, 6:01:28 PM8/14/16
to
On Friday, 12 August 2016 12:12:07 UTC+3, jacob navia wrote:
> Le 12/08/2016 à 10:08, Öö Tiib a écrit :
> > I think that C++11 should also print X!. Where you took that from?
>
> Chandler-Carruth
> Lead developper of the "clang" compiler project. And before you write "I
> think that..." can you compile that?
>

I did compile it on couple quite recent compilers:

g++ -v 2>&1 | grep version; g++ -std=c++11 -O0 -Wall -pedantic -pthread main.cpp && ./a.out

gcc version 6.1.0 (GCC)

X!

clang++ -v 2>&1 | grep version; clang++ -std=c++11 -stdlib=libc++ -O0 -Wall -pedantic -pthread main.cpp && ./a.out

clang version 3.8.0 (tags/RELEASE_380/final 263969)

X!

It is likely some sort of language lawyer level issue with normative
texts and so should be repaired in text of standard if it is dim.

Melzzzzz

unread,
Aug 14, 2016, 8:07:26 PM8/14/16
to
On Sun, 14 Aug 2016 23:08:05 +0200
jacob navia <ja...@jacob.remcomp.fr> wrote:

> Le 14/08/2016 à 22:55, Chris Vine a écrit :
> > On Sun, 14 Aug 2016 22:52:02 +0200
> > jacob navia <ja...@jacob.remcomp.fr> wrote:
> >> [drivel snipped]
> >
> > You are still missing the point. Your example is highly
> > artificial.
>
>
> Of course not!!!!!!!
>
> That is a condensate of a problem that will appear in a huge program
> where conceptually those 12 lines are dispersed in several different
> files across several classes and templates and what have you!!!!!

That program is broken, then. Heaving non explicit conversion
constructor is bug waiting to happen.
Actually, except conversion from char* to std::string I never saw any
other in C++ programs...


Melzzzzz

unread,
Aug 14, 2016, 8:12:25 PM8/14/16
to
C++11 makes C++ very pleasant to program in.

Ian Collins

unread,
Aug 15, 2016, 1:20:40 AM8/15/16
to
On 08/15/16 12:07 PM, Melzzzzz wrote:
>
> That program is broken, then. Heaving non explicit conversion
> constructor is bug waiting to happen.
> Actually, except conversion from char* to std::string I never saw any
> other in C++ programs...

What he said!

--
Ian

Ike Naar

unread,
Aug 15, 2016, 2:00:49 AM8/15/16
to
Jacob has a valid point here. If a minimal example highlights a
problem, then why would it make more sense to post a huge pile of
"real" code instead of the minimal example?

And why would a huge pile of code be more "real" than a minimal example?
What exactly is "unreal" about the minimal example?

You're calling Jacob.
Why not doing the work yourself, and extend/embellish the given
minimal example to make it "real", and post the result here?
And, if you wish, please point out which embellishments make the
extended example more appropriate to illustrate the underlying
problem than the minimal example would.

Bo Persson

unread,
Aug 15, 2016, 2:58:42 AM8/15/16
to
On 2016-08-15 08:00, Ike Naar wrote:
> On 2016-08-14, Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>> On Sun, 14 Aug 2016 23:08:05 +0200
>> jacob navi
>>> THAT IS A MINIMAL EXAMPLE OF THE PROBLEM MAN!
>>
>> Hot air. It isn't a problem.
>>
>> I'll call you. Give me real code you might actually want to write for
>> a meaningful purpose where this is a live issue. Post it to a pasting
>> service if you think that would be better. If you could explain what
>> result you were expecting and why it didn't deliver it, and how it
>> relates to the code you posted, that would help also.
>
> Jacob has a valid point here. If a minimal example highlights a
> problem, then why would it make more sense to post a huge pile of
> "real" code instead of the minimal example?
>
> And why would a huge pile of code be more "real" than a minimal example?
> What exactly is "unreal" about the minimal example?
>

Because the example contains code you would never write in the first
place. Everyone knows that if you have both a converting constructor and
a conversion operator in the same code, the code is broken.

If you try Jacob's favorite language C, it too has problems

#define min(a, b) a < b ? a : b

x = min(x++, y++)

This also gives unexpected results. Is C also broken?



Bo Persson

Ike Naar

unread,
Aug 15, 2016, 3:14:14 AM8/15/16
to
On 2016-08-15, Bo Persson <b...@gmb.dk> wrote:
> On 2016-08-15 08:00, Ike Naar wrote:
>> On 2016-08-14, Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>>> On Sun, 14 Aug 2016 23:08:05 +0200
>>> jacob navi
>>>> THAT IS A MINIMAL EXAMPLE OF THE PROBLEM MAN!
>>>
>>> Hot air. It isn't a problem.
>>>
>>> I'll call you. Give me real code you might actually want to write for
>>> a meaningful purpose where this is a live issue. Post it to a pasting
>>> service if you think that would be better. If you could explain what
>>> result you were expecting and why it didn't deliver it, and how it
>>> relates to the code you posted, that would help also.
>>
>> Jacob has a valid point here. If a minimal example highlights a
>> problem, then why would it make more sense to post a huge pile of
>> "real" code instead of the minimal example?
>>
>> And why would a huge pile of code be more "real" than a minimal example?
>> What exactly is "unreal" about the minimal example?
>
> Because the example contains code you would never write in the first
> place. Everyone knows that if you have both a converting constructor and
> a conversion operator in the same code, the code is broken.

That doesn't explain why a "real" would illustrate this better than
the minimal example. If the minimal example is broken, the "real"
example will also be broken, but you'd have to spend far more energy
to find this out, because of the sheer size of the "real" example.

Ian Collins

unread,
Aug 15, 2016, 4:54:37 AM8/15/16
to
Probably because the "problem" is something that wouldn't show up in
real code. It's easy to find contrived examples, it's much harder
finding coding standards that would allow them!

--
Ian

David Brown

unread,
Aug 15, 2016, 5:18:35 AM8/15/16
to
Unfortunately, many programmers don't use coding standards as such, or
formal code reviews, or good test procedures. People /do/ write code
that allows implicit conversions that they had not expected, or did not
intend, especially pre C++11. Getting it all right can be difficult
(again, especially pre C++11) - look at the "safe bool idiom".

Of course this does not mean that C++ is "broken" - it just illustrates
one of the possible dangers or sources of confusion in the language.
Like many features, implicit conversions can be used to write clear,
concise, safe and efficient code - but they can also lead to mistakes.



Chris Vine

unread,
Aug 15, 2016, 8:37:22 AM8/15/16
to
On Mon, 15 Aug 2016 11:18:25 +0200
David Brown <david...@hesbynett.no> wrote:
> On 15/08/16 10:54, Ian Collins wrote:
> > On 08/15/16 07:14 PM, Ike Naar wrote:
[snip]
> >> That doesn't explain why a "real" would illustrate this better than
> >> the minimal example. If the minimal example is broken, the "real"
> >> example will also be broken, but you'd have to spend far more
> >> energy to find this out, because of the sheer size of the "real"
> >> example.
> >
> > Probably because the "problem" is something that wouldn't show up in
> > real code. It's easy to find contrived examples, it's much harder
> > finding coding standards that would allow them!
> >
>
> Unfortunately, many programmers don't use coding standards as such, or
> formal code reviews, or good test procedures. People /do/ write code
> that allows implicit conversions that they had not expected, or did
> not intend, especially pre C++11. Getting it all right can be
> difficult (again, especially pre C++11) - look at the "safe bool
> idiom".
>
> Of course this does not mean that C++ is "broken" - it just
> illustrates one of the possible dangers or sources of confusion in
> the language. Like many features, implicit conversions can be used to
> write clear, concise, safe and efficient code - but they can also
> lead to mistakes.

The undesirability of providing conversion constructors without a lot
of careful prior thought is, I think, well recognised these days.

However, although the issue in the original posting did indeed involve
an implicit conversion from int to X as one part of its mode of
operation, the "bug" referred to also involved the interaction of this
with function overloading and compile time constants, of a bizarre
kind. It involved passing an integer member of a zero initialized
temporary of an aggregate type S ('S().n'), and it was alleged that in
C++11/14, the test case should print "Pointer!" because in C++11/14 the
expression comprises a constant expression of value 0, which would be a
match for the function overload taking void* by virtue of it also being
a null pointer constant.

This is entirely contrived, and it is pretty much inconceivable that
this situation would arise in real code, even with a developer
taking a punt with implicit conversions. No one in their right minds
is going to pass an integer member of a temporary zero-initialized
aggregate literal type to another function using the dot operator
because it is completely without purpose.

As it happens none of the compilers I have tested this with (g++ going
from version 4.4 to 6.1 and clang++ 3.8.1) actually behave like this.
They all print "X!" whether compiled with -std=c++98 or
-std=c++{0x,11,14}.

I can't even get this to misbehave, using either g++ or clang++:

constexpr int zero = 0;
f(zero);

It looks as if constexpr integers of value 0 are not in fact null
pointer constants in C++11/14.

Chris

David Brown

unread,
Aug 15, 2016, 8:56:13 AM8/15/16
to
I agree that this exact example is contrived, and I also failed to
trigger the inconsistent behaviour that has been claimed for it.

But I think the more general point of programmers sometimes getting
unexpected behaviour from implicit conversions stands. Conversions
involving 0 can be particularly confusing because they may end up as
pointers, or as integers, depending on the circumstances of the code.
(The rules of C++ for this sort of thing are, I believe, unambiguous -
but they are not always simple.)

All I am really saying here is that this kind of thing can be quite
complicated, and if due care is not taken (and due care is not always
taken when programming), then accidents can happen in /real/ code.

Some of the new features of C++11, such as nullptr and explicit
conversion operators, address this and make it easier to write code the
does what you want (while avoiding writing code that also does things
you don't want!). This means that if you are using C++11 onwards, you
must take care to use these new features appropriately - and if you are
using C++03 or earlier, you must be even more careful.

(I don't mean this is a problem with C++ - it is simply one of the costs
of the powerful language.)

Chris Vine

unread,
Aug 15, 2016, 9:21:45 AM8/15/16
to
On Mon, 15 Aug 2016 14:55:59 +0200
David Brown <david...@hesbynett.no> wrote:
[snip]
> I agree that this exact example is contrived, and I also failed to
> trigger the inconsistent behaviour that has been claimed for it.
>
> But I think the more general point of programmers sometimes getting
> unexpected behaviour from implicit conversions stands. Conversions
> involving 0 can be particularly confusing because they may end up as
> pointers, or as integers, depending on the circumstances of the code.
> (The rules of C++ for this sort of thing are, I believe, unambiguous -
> but they are not always simple.)
>
> All I am really saying here is that this kind of thing can be quite
> complicated, and if due care is not taken (and due care is not always
> taken when programming), then accidents can happen in /real/ code.
>
> Some of the new features of C++11, such as nullptr and explicit
> conversion operators, address this and make it easier to write code
> the does what you want (while avoiding writing code that also does
> things you don't want!). This means that if you are using C++11
> onwards, you must take care to use these new features appropriately -
> and if you are using C++03 or earlier, you must be even more careful.
>
> (I don't mean this is a problem with C++ - it is simply one of the
> costs of the powerful language.)

I think we can happily agree on this.

Anyway, I have found the answer to the original point. In §4.10/1 of
C++11 as originally published a null pointer constant was defined as
follows:

"A null pointer constant is an integral constant expression (5.19)
prvalue of integer type that evaluates to zero or a prvalue of type
std::nullptr_t."

DR903 (also incorporated in C++14) corrected this to read:

"A null pointer constant is an integer literal (2.14.2) with value
zero or a prvalue of type std::nullptr_t."

So the correct behaviour in C++14 or with DR903 is to print "X!".

My example:

constexpr int zero = 0;
f(zero);

was bogus even under original C++11 because zero is not a prvalue.

Interestingly I have found a gcc bug. This:

f(int{});

prints "X!" because int{} is not an integer literal, and it does
do so with gcc and lang-3.8.1. However this prints "Pointer!" with
gcc-4.6.1 but not clang:

f(int());

which seems to me to be wrong.

Chris

Chris Vine

unread,
Aug 15, 2016, 9:50:18 AM8/15/16
to
On Mon, 15 Aug 2016 14:21:28 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
However this prints "Pointer!" with
> gcc-4.6.1 but not clang:
>
> f(int());
>
> which seems to me to be wrong.

Ah, it is a gcc bug but appears to be a deliberate one to maintain
compatibility with C++98. If you want the more bullet-proof C++14
conforming behaviour with gcc then it appears you have to use the
'f(int{})' form.

Chris

Alf P. Steinbach

unread,
Aug 15, 2016, 12:35:59 PM8/15/16
to
Good work, that clears up a lot of things for me.

So, it's C++14 that changed the requirement from constant expression to
literal.

3rd revision of beliefs... :-)


Cheers,

- Alf

Öö Tiib

unread,
Aug 15, 2016, 12:55:57 PM8/15/16
to
On Sunday, 14 August 2016 02:37:04 UTC+3, jacob navia wrote:
> Le 12/08/2016 à 08:57, jacobnavia a écrit :
>
>
> Please look at
> https://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Clang-Defending-C-from-Murphy-s-Million-Monkeys
>
> In that talk, see the slide and discussion. Starts around minute 47 of
> the video

Note that it is speech from February 2012. I can't find compilers that
print X! at 2016. Whatever caused his opinion that the (unusual) code
in your original post must print "Pointer!" must be is now gone.

However I agree with you that initialization of C++11 was screwed up.

Anyone who makes implicit conversion constructors, conversion
operators, constructor templates, constructors that accept
'std::initializer_list' and/or something that is multiple things from
that list will likely get rather bad review from me.

From bright side IMHO it is sole thing that C++11 broke. Rest of the
features that C++11 added I like very lot.

Richard

unread,
Aug 15, 2016, 1:17:16 PM8/15/16
to
[Please do not mail me a copy of your followup]

ja...@jacob.remcomp.fr spake the secret code
<nolgpd$4ah$1...@dont-email.me> thusly:

>Le 12/08/2016 à 23:43, woodb...@gmail.com a écrit :
>> I support law abiding citizens having guns
>
>Yes, you must live [...]

*plonk*

You were already very near to entering my kill file with your ranty
bitching.

Now that you've demonstrated no self-control, welcome to my KILL file.

You and wood brain will enjoy arguing with each other while I
blissfully ignore you.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

woodb...@gmail.com

unread,
Aug 15, 2016, 1:57:55 PM8/15/16
to
On Monday, August 15, 2016 at 11:55:57 AM UTC-5, Öö Tiib wrote:
> On Sunday, 14 August 2016 02:37:04 UTC+3, jacob navia wrote:
> > Le 12/08/2016 à 08:57, jacobnavia a écrit :
> >
> >
> > Please look at
> > https://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Clang-Defending-C-from-Murphy-s-Million-Monkeys
> >
> > In that talk, see the slide and discussion. Starts around minute 47 of
> > the video
>
> Note that it is speech from February 2012. I can't find compilers that
> print X! at 2016. Whatever caused his opinion that the (unusual) code
> in your original post must print "Pointer!" must be is now gone.
>
> However I agree with you that initialization of C++11 was screwed up.
>
> Anyone who makes implicit conversion constructors, conversion
> operators, constructor templates, constructors that accept
> 'std::initializer_list' and/or something that is multiple things from
> that list will likely get rather bad review from me.
>

The standard containers do some of those things.
I manage to avoid most of them.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Manfred

unread,
Aug 15, 2016, 2:17:51 PM8/15/16
to
On 08/14/2016 09:23 PM, Ian Collins wrote:
>
> Which compilers are they?
>

There's at least clang c++ 2011, as the initial post in this thread
reported, and Chris Vine just mentioned here a similar bug in gcc 4.6.1:
> However this prints "Pointer!" with
> gcc-4.6.1 but not clang:
>
> f(int());
>
> which seems to me to be wrong.

Nonetheless, I would like to make clear that in fact I just love C++. My
remark was about a "risk" for C++ to get polluted along the way, not
that this is actually happened so far.

Regards

Mr Flibble

unread,
Aug 15, 2016, 2:54:05 PM8/15/16
to
Many hours earlier I said what was being passed had a *name* which
seemed to confuse you. Literals don't have names.

/Flibble

jacob navia

unread,
Aug 15, 2016, 5:41:00 PM8/15/16
to
Le 15/08/2016 à 19:17, Richard a écrit :
> [Please do not mail me a copy of your followup]
>
> ja...@jacob.remcomp.fr spake the secret code
> <nolgpd$4ah$1...@dont-email.me> thusly:
>
>> Le 12/08/2016 à 23:43, woodb...@gmail.com a écrit :
>>> I support law abiding citizens having guns
>>
>> Yes, you must live [...]
>
> *plonk*

The U.S.A. the only country in the civilized world where people go
around with guns killing themselves.
>
> You were already very near to entering my kill file with your ranty
> bitching.
>

I am happy that I enter your kill file without being killed by your gun.
I am, and have always been, unarmed. I do not take a gun with me to kill
other fellow beings.

I just do not kill people.

> Now that you've demonstrated no self-control, welcome to my KILL file.
>

If you think that not killing people and not having guns is a sin...

Well I can't do anything for you either.

> You and wood brain will enjoy arguing with each other while I
> blissfully ignore you.
>

You are so convinced of your own importance. You and your gun.


Öö Tiib

unread,
Aug 15, 2016, 11:35:27 PM8/15/16
to
There are no controversy. Similarly each of standard containers has
something documented as source of undefined behavior but code with
undefined behavior will likely get bad review from me.

Luca Risolia

unread,
Sep 5, 2016, 9:58:40 AM9/5/16
to
On 13/08/2016 00:19, jacobnavia wrote:
> Le 12/08/2016 à 08:57, jacobnavia a écrit :
>> The chief developper of clang has pointed out that this example CHANGES
>> BEHAVIOR between c++ 2008 and c++ 2011
>>
>> #include <iostream>
>> struct S { int n; };
>> struct X { X(int) {} };
>> void f(void *) {
>> std::cerr << "Pointer!\n";
>> }
>> void f(X) {
>> std::cerr << "X!\n";
>> }
>> int main() {
>> f(S().n);
>> }
>>
>
> Look I do not know c++ but anyway...

Fortunately, no sane C++ developer would ever need to write such a
crappy piece of code.

0 new messages