Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning a double to a struct

Tags:

c++

I stumbled upon something the other day in the code of a colleague and I want to understand how/why this works.

He uses a struct like this

 struct my_struct
 {

   my_struct(){ /* default constructor*/};
   my_struct(char c){ /*some special constructor*/};
   // other stuff
   my_struct& operator=(const my_struct &ms){ /* assignment */};
  };

Originally through a typo he figured out that the following works

  my_struct ms;
  double a;
  ms = a;

I have worked out that this is equal (in the sense of gives the same final struct ms) to the following

  my_struct ms;
  double a;
  my_struct ms2((char) a);
  ms=ms2;

But I don't know why. Personally, I think this should not work, because there is no assign operator for double and my_struct and additionally because there is no constructor for my_struct using a double.

I tried to google this, but did not find anything relevant.

@ user657267: i wanted to keep it as short as possible, you could add a line a=5; or whatever the same would apply.

like image 673
Bort Avatar asked Jul 08 '14 07:07

Bort


1 Answers

During the compilation this:

ms = a;

attempts to resolve an assignment of one or more of the following immediate forms

my_struct& operator ()(double)
my_struct& operator ()(double&)
my_struct& operator ()(const double&)

and a litany of other potential conversion from double. And none is found. In fact, only the following is discovered:

my_struct& operator=(const my_struct &ms)

which indicates the compiler does allow assignment via a const-reference of another my_struct. At that time a conversion constructor is sought, starting with the most immediate conversion (explicit to the type double:

my_struct(double)
my_struct(double&)
my_struct(const double&)

It is important to note such a constructor cannot mandate explicit use. We're implicitly constructing a temporary, and as such explicit mandate is off the reservation.

Anyway, again, none is found. Before giving up the compiler attempts to locate a constructor of any form that can convert from double to whatever the fundamental construction requires and said constructor supports implicit construction. In effect, something of the form

my_struct(<<something that can be converted from a double>>)

And again, the constructor cannot be explicit. As it turns out, this search does find this:

my_struct(char)

because double can be converted to char (albeit poorly and likely not what you want). The entire chain is a little (ok, a lot) more complicated than that, but that is the crux of it.

You can avoid this implicit construction by ensuring that constructor is only explicit in usage, but that is a double-edge sword, so care is required. Use of explicit can be somewhat harsh. Doing this:

explicit my_struct(char)

will squelch the unintended implicit construction when converting double to char. But I warn you; it will also squelch the ability to do this:

char x = 'a';
my_struct ms;
ms = x;

because now my_struct cannot be implicitly constructed at all from char, by conversion or otherwise. There are multiple ways around this, including defining a specific assignment operator for the type (takes a double) or a specific conversion constructor (takes a double). How you approach that I leave to you.

like image 125
WhozCraig Avatar answered Sep 28 '22 17:09

WhozCraig