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

Strange convertion

111 views
Skip to first unread message

Vianney Lançon

unread,
Oct 19, 2012, 4:04:58 PM10/19/12
to
Hello,

while compiling our code we found that a wrong constructor was called.

The code was something like that.


#include <iostream>
struct Toto
{
Toto(unsigned short a[2]){ x=a[0]; y=a[1];}
unsigned short x, y;
};
void print(const Toto& toto)
{
std::cout<<toto.x<<" "<<toto.y<<std::endl;
}
int main()
{
print(false); // <= convert false to Toto
return 0;
}


Because the constructor of Toto is not explicit it is normal that
unsigned short[4] can be converterd to Toto.

But I do not understand by what mechanisme the bool value false can be
convert into unsigned short[4].

Because it doesn't compile if i change the value from false to true it
's probably because of some convertion from false to 0 literal.

This code, compile on VC++10 & commeau online so i guess, it probalby
resepect the standard. Do you have any clue how?

--
Vianney Lançon


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
Oct 19, 2012, 6:35:35 PM10/19/12
to
Am 19.10.2012 22:04, schrieb Vianney Lançon:
> while compiling our code we found that a wrong constructor was called.

No, it isn't.

> The code was something like that.
>
>
> #include <iostream>
> struct Toto
> {
> Toto(unsigned short a[2]){ x=a[0]; y=a[1];}
> unsigned short x, y;
> };

This constructor signature is a red herring. It is equivalent to the
following one:

Toto(unsigned short a*){ x=a[0]; y=a[1];}

thus you effectively have declared a constructor that accepts a pointer
value to unsigned short. This is one of the inheritances of C: Arrays
cannot be used as function parameters or function return types. If you
attempt to declare such a function parameter, it will silently be
considered as a pointer to the array's element type. Personally I find
the validity of this code quite unfortunate, it should better have been
made ill-formed (like attempting to declare an array type as return type).

> void print(const Toto& toto)
> {
> std::cout<<toto.x<<" "<<toto.y<<std::endl;
> }
> int main()
> {
> print(false); // <= convert false to Toto

This works, because you are effectively providing a null pointer
constant to a function that accepts a pointer value. This is valid and
will simply call the function with a null pointer value.

> return 0;
> }
>
>
> Because the constructor of Toto is not explicit it is normal that
> unsigned short[4] can be converterd to Toto.

Try to provide an argument that is an array unsigned short[1] or
unsigned short[5] and you should see that it becomes accepted, too,
because all of these convert to unsigned short*. This is a very
dangerous thing, so better don't declare such a function. If you really
want to declare a function that only accepts an array, you need to use a
parameter of reference to arrayr type, such as

Toto(unsigned short (&a)[2]){ x=a[0]; y=a[1];}

or even

Toto(const unsigned short (&a)[2]){ x=a[0]; y=a[1];}

> But I do not understand by what mechanisme the bool value false can be
> convert into unsigned short[4].

See above, it is a null pointer constant accepted by a function taking a
pointer.

> Because it doesn't compile if i change the value from false to true it
> 's probably because of some convertion from false to 0 literal.

The reason is, that 'true' is not a null pointer constant (The value is
equivalent to '1'). I should add here that the C++ committee is
currently considering to reduce the amount of numbers to specify such a
null pointer constant, because it causes also problems in templates.
Assuming the current suggestion, as described here:

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903

will be accepted, the value 'false' would no longer be an acceptable
null pointer value.

HTH & Greetings from Bremen,

Daniel Krügler


--

red floyd

unread,
Oct 19, 2012, 6:36:03 PM10/19/12
to
On 10/19/2012 1:04 PM, Vianney Lançon wrote:
> Hello,
>
> while compiling our code we found that a wrong constructor was called.
>
> The code was something like that.
>
>
> #include <iostream>
> struct Toto
> {
> Toto(unsigned short a[2]){ x=a[0]; y=a[1];}
> unsigned short x, y;
> };
> void print(const Toto& toto)
> {
> std::cout<<toto.x<<" "<<toto.y<<std::endl;
> }
> int main()
> {
> print(false); // <= convert false to Toto
> return 0;
> }
>
>
> Because the constructor of Toto is not explicit it is normal that
> unsigned short[4] can be converterd to Toto.
>
> But I do not understand by what mechanisme the bool value false can be
> convert into unsigned short[4].
>
> Because it doesn't compile if i change the value from false to true it
> 's probably because of some convertion from false to 0 literal.

I believe it's because unsigned short[2] decays to unsigned short*.
The chain then is false => 0 => (unsigned short*)0.


--

Ike Naar

unread,
Oct 19, 2012, 6:36:57 PM10/19/12
to
On 2012-10-19, Vianney Lan?on <to...@toto.com> wrote:
> Hello,
>
> while compiling our code we found that a wrong constructor was called.
>
> The code was something like that.
>
>
> #include <iostream>
> struct Toto
> {
> Toto(unsigned short a[2]){ x=a[0]; y=a[1];}
> unsigned short x, y;
> };
> void print(const Toto& toto)
> {
> std::cout<<toto.x<<" "<<toto.y<<std::endl;
> }
> int main()
> {
> print(false); // <= convert false to Toto
> return 0;
> }
>
>
> Because the constructor of Toto is not explicit it is normal that
> unsigned short[4] can be converterd to Toto.
>
> But I do not understand by what mechanisme the bool value false can be
> convert into unsigned short[4].
>
> Because it doesn't compile if i change the value from false to true it
> 's probably because of some convertion from false to 0 literal.
>
> This code, compile on VC++10 & commeau online so i guess, it probalby
> resepect the standard. Do you have any clue how?

The type of the parameter in Toto(unsigned short a[2]) decays into a
pointer-to-short. The declaration is equivalent to Toto(unsigned short *a);
0, a null pointer constant, is accepted as a pointer-to-short.


--

red floyd

unread,
Oct 20, 2012, 1:55:07 AM10/20/12
to
On 10/19/2012 3:36 PM, red floyd wrote:
> On 10/19/2012 1:04 PM, Vianney Lan�on wrote:
>> Hello,
>>
>> while compiling our code we found that a wrong constructor was called.
>>
>> The code was something like that.
>>
>>
>> #include <iostream>
>> struct Toto
>> {
>> Toto(unsigned short a[2]){ x=a[0]; y=a[1];}
>> unsigned short x, y;
>> };
>> void print(const Toto& toto)
>> {
>> std::cout<<toto.x<<" "<<toto.y<<std::endl;
>> }
>> int main()
>> {
>> print(false); // <= convert false to Toto
>> return 0;
>> }
>>
>>
>> Because the constructor of Toto is not explicit it is normal that
>> unsigned short[4] can be converterd to Toto.
>>
>> But I do not understand by what mechanisme the bool value false can be
>> convert into unsigned short[4].
>>
>> Because it doesn't compile if i change the value from false to true it
>> 's probably because of some convertion from false to 0 literal.
>
> I believe it's because unsigned short[2] decays to unsigned short*.
> The chain then is false => 0 => (unsigned short*)0.

If you want an array only, pass a reference to it.

Toto(unsigned short (&a)[2]);

This will *ONLY* accept an array of 2 shorts.
0 new messages