Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Managing Implicit Type Conversion in C++

I'm working on code that does nearest-neighbor queries. There are two simple ideas that underlie how a user might query for data in a search:

  • closest N points to a given point in space.
  • all points within a given distance.

In my code, Points are put into a PointList, and the PointList is a container has the job of keeping track of the points that have been found in the search.

Right now my PointList object has one constructor:

PointList( unsigned int maxvals ); // #1

The next two constructors that I'd like to add are these:

PointList( float maxdist ); // #2
PointList( unsigned int maxvals, float maxdist ); // #3

My question is: how do I ensure that my users and the C++ compiler will generate the right constructor for the PointList and differentiates between constructors 1 and 2? Should I just implement #3 and provide constants that define arbitrary large values for maxvals and maxdist? Another alternative might be to write another system of lightweight objects that govern the logic for adding Points to the list, but that feels like overkill for such a simple idea.

I'm really trying to make this transparent for my users, who are mostly scientists who have learned C++ sometimes without the benefit of formal education. Thanks!

like image 532
James Thompson Avatar asked Dec 20 '25 02:12

James Thompson


2 Answers

Why not use factory methods instead of constructors? Factory methods have the advantage of customizable names.


static PointList createNearestValues(unsigned int maxvals) {}
static PointList createByDistance(float maxdist) {}
like image 144
Hans Malherbe Avatar answered Dec 22 '25 18:12

Hans Malherbe


Overload resolution for integer types happen on two categories, which can be very roughly summarized to

  • Promotion: This is a conversion from types smaller than int to int or unsigned int, depending on whether int can store all the values of the source type.
  • Conversion: This is a conversion from any integer type to another integer type.

Similar, conversion for floating point types happen on two categories

  • Promotion: This is a conversion from float to double
  • Conversion: This is a conversion from any floating point type to another floating point type

And there is a conversion from integer to floating or back. This is ranked as a conversion, rather than a promotion. A promotion is ranked better than a conversion, and where only a promotion is needed, that case will be preferred. Thus, you can use the following constructors

PointList( int maxVals );
PointList( unsigned int maxVals );
PointList( long maxVals );
PointList( unsigned long maxVals );

PointList( double maxDist );
PointList( long double maxDist );

For any integer type, this should select the first group of constructor. And for any floating point type, this should select the second group of constructors. Your original two constructors could easily result in an ambiguity between float and unsigned int, if you pass an int, for example. For the other, two argument constructor, you can go with your solution, if you want.


That said, i would use a factory function too, because deciding on the type the meaning of the parameter is quite fragile i think. Most people would expect the following result to equal

PointList p(floor(1.5));
PointList u((int)1.5);

But it would result in a different state of affairs.

like image 22
Johannes Schaub - litb Avatar answered Dec 22 '25 16:12

Johannes Schaub - litb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!