1

在 C++ 中重载函数时,对于以下涉及模糊类型的问题,是否有任何优雅的解决方案?我想要两种不同的类型:“距离”和“角度”,它们在语义上意味着不同的东西,但实际上可能具有相同的类型。当尝试在 C++ 中执行此操作时,我遇到了函数重载的问题:

typedef float distance;
typedef float angle;

class Velocity {
public:
    Velocity(distance dx, distance dy) { /* impl */ }
    Velocity(angle theta, distance magnitude) { /* impl */ }
};

当我尝试编译它时,我得到“无法重新声明构造函数”。但是(由于某种原因,我无法弄清楚)当我在我的实际应用程序代码库中执行此操作时,该类会编译,但后来当我执行类似的操作时,我会收到“对 'Velocity' 的构造函数的调用不明确” :

distance dx;
distance dy;
Velocity v(dx, dy);

这个问题有什么优雅的解决方案吗?一种不令人满意的解决方案是仅更改这些数量之一的类型

typedef double distance;

但这显然无法扩展,因为只有几种不同的浮点类型。我尝试的另一个选择是使用模板

template <typename distance, typename angle>
class Velocity {
public:
    Velocity(distance dx, distance dy) : dx(dx), dy(dy) {  }
    Velocity(angle theta, distance magnitude) { }
};

但是如果我用相同的类型实例化它们,我会得到“'Velocity'的多个重载实例化为相同的签名'void(float,float)'”。即使这可行,它仍然会有点不满意,因为我必须Velocity在许多地方为类型添加模板参数。

4

3 回答 3

3

typedef不创建新类型,它只是为具有不同名称并且可能在不同命名空间中的类型创建别名,类似于using.

因此,您的两个构造函数都是有效的float, float

如果你想创建一个实际的新类型,你可以创建一个包含该类型的新结构或类。C++ chrono 类型,例如std::chrono::seconds包装整数。这样做还允许更具体的重载,例如您可能会说displacement = velocity * time,尽管这样做可能很快需要许多类型和运算符重载。

float在重载 say和时也要小心double,我当然不会这样做,因为它们有不同的含义。考虑像0and这样的文字1,或者像int.

于 2019-04-10T22:25:46.570 回答
2

您可以围绕距离和角度创建一个非常轻量级的包装器,然后使用文字!

struct Distance {
    double value;
};
struct Angle {
    double value;
};

class Velocity {
   public:
    Velocity(Distance dx, Distance dy) { /* impl */ }
    Velocity(Angle theta, Distance magnitude) { /* impl */ }
};

然后,您可以在构造时包装值Velocity

// Create by distance
Velocity v1(Distance{5.0}, Distance{10.0}); 
// Create by angle
Velocity v2(Angle{1.5}, Distance{1.0}); 

我们还可以提供用户定义的文字,以便您可以这样v1编写v2

Velocity v1(5.0_meters, 10.0_meters);
Velocity v2(60.0_degrees, 10.0_meters);

编写用户定义的文字非常简单:

Distance operator ""_meters(double value) {
    return Distance{value}; 
}
Angle operator ""_degrees(double value) {
    return Angle{value / 180.0 * PI}; 
}
于 2019-04-10T22:43:27.137 回答
0

是的,你需要不同的类型才能有重载。

一种解决方案是通过更改函数名称来避免重载。

另一种是通过创建包装浮动的 aclass或 a来创建自定义类型。struct

然后,您可以重载一些运算符以实现所需的行为,但在我看来,最好更改函数的名称

于 2019-04-10T22:26:36.317 回答