简体   繁体   English

在C ++中管理隐式类型转换

[英]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. 最近的N指向空间中的给定点。
  • 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. 在我的代码中,Points被放入PointList,而PointList是一个容器,其工作是跟踪在搜索中找到的点。

Right now my PointList object has one constructor: 现在我的PointList对象有一个构造函数:

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? 我的问题是:我如何确保我的用户和C ++编译器将为PointList生成正确的构造函数并区分构造函数1和2? Should I just implement #3 and provide constants that define arbitrary large values for maxvals and maxdist? 我应该只实现#3并提供定义maxvals和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. 另一个替代方案可能是编写另一个轻量级对象系统来管理将Points添加到列表中的逻辑,但这对于这样一个简单的想法来说就像是有点过分。

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. 我真的试图让我的用户透明,这些用户大多是在没有正规教育的情况下学习过C ++的科学家。 Thanks! 谢谢!

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) {}

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. 升级:这是从小于int类型到intunsigned int ,具体取决于int是否可以存储源类型的所有值。
  • 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 促销:这是从floatdouble的转换
  • 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. 例如,如果传递一个int ,那么原始的两个构造函数很容易导致floatunsigned int之间的歧义。 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. 但这会导致不同的事态。

Consider using true typedefs . 考虑使用true typedef It's a little more effort on the part of your client code, but you're guaranteed correctness. 您的客户端代码需要付出更多努力,但保证您的正确性。

Call PointList(10) for the first and PointList(10f) for the second. 为第一个调用PointList(10),为第二个调用PointList(10f)。

For the second, you can also use 10.0. 对于第二个,您也可以使用10.0。

If constructors #1 and #2 are present the correct constructor will be called if the value you insert is of float or int and no conversion should take place. 如果构造函数#1和#2存在,如果您插入的值是float或int,则将调用正确的构造函数,并且不应进行任何转换。 So just ensure that you make the types of the numbers you use to call explicit (ie 1f and 1). 因此,只需确保您使用显式调用的数字类型(即1f和1)。 Constructor #3 doesn't seem to be much of an option as it is not really necessary and would just confuse users of your code. 构造函数#3似乎不是一个选项,因为它不是真正必要的,只会混淆代码的用户。 If you need default values for either number you could use 如果您需要任何一个号码的默认值,您可以使用

PointList(int max, float max=VALUE)

and

PointList(float max, int max=VALUE)

Again: this seems to do more harm then code in terms of code readability. 再说一遍:在代码可读性方面,这似乎比代码更有害。

这要求对过载分辨率进行良好的阅读。

I would definitely use explicit constructors. 我肯定会使用显式构造函数。 In the example the unsigned integer does not convert implicitly. 在示例中,无符号整数不会隐式转换。

class A
{
public:
    explicit A(float f){}
    explicit A(int i){}
};

void test(){
    unsigned int uinteger(0);
    A a1(uinteger);        //Fails, does not allow implicit conversions

    A a2((float)uinteger); //OK, explicit conversion

    float f(0.0);
    A a3(f);               //OK

    int integer(0);
    A a4(integer);         //OK
}

The error message is easy enough to understand: 错误消息很容易理解:

: error C2668: 'A::A' : ambiguous call to overloaded function
: could be 'A::A(int)'
: or       'A::A(float)'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM