使用 typedef 时的 C++ 模糊构造函数
C++ ambiguous constructor when using typedefs
对于以下C++中函数重载时类型不明确的问题,有没有优雅的解决方案?我想要两种不同的类型:"distance" 和 "angle",它们在语义上意味着不同的东西,但实际上可能具有相同的类型。当尝试在 C++ 中执行此操作时,我 运行 遇到函数重载问题:
typedef float distance;
typedef float angle;
class Velocity {
public:
Velocity(distance dx, distance dy) { /* impl */ }
Velocity(angle theta, distance magnitude) { /* impl */ }
};
当我尝试编译它时,我得到 "constructor cannot be redeclared"。但是(出于某种原因我无法弄清楚)当我在我的实际应用程序代码库中执行此操作时,class 会编译,但后来我在执行以下操作时得到 "call to constructor of 'Velocity' is ambiguous":
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) { }
};
但是如果我用相同的类型实例化它们,我会得到 "multiple overloads of 'Velocity' instantiate to the same signature 'void (float, float)'"。即使这可行,它仍然有点不令人满意,因为我必须在许多地方向 Velocity
类型添加模板参数。
typedef
不会创建新类型,它只是为具有不同名称并可能在不同命名空间中的类型创建别名,类似于 using
.
因此,您的两个构造函数实际上都是 float, float
。
如果您想创建一个实际的新类型,您可以创建一个新结构或 class 包含该类型。 C++ 计时类型,例如 std::chrono::seconds
包装一个整数。这样做还允许更具体的重载,例如您可能会说 displacement = velocity * time
,尽管这样做可能很快需要许多类型和运算符重载。
在重载float
和double
时也要小心,我当然不会这样做,以至于它们具有不同的含义。考虑像 0
和 1
这样的文字,或者像 int
.
这样的类型的隐式转换会发生什么
是的,您需要不同的类型才能重载。
一种解决方案是通过更改函数名称避免重载。
另一种方法是通过创建 class
或 struct
包装浮点数来创建您的自定义类型。
然后您可以重载一些运算符以实现所需的行为,但在我看来,最好更改函数的名称
您可以围绕距离和角度创建一个非常轻量级的包装器,然后使用文字!
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};
}
对于以下C++中函数重载时类型不明确的问题,有没有优雅的解决方案?我想要两种不同的类型:"distance" 和 "angle",它们在语义上意味着不同的东西,但实际上可能具有相同的类型。当尝试在 C++ 中执行此操作时,我 运行 遇到函数重载问题:
typedef float distance;
typedef float angle;
class Velocity {
public:
Velocity(distance dx, distance dy) { /* impl */ }
Velocity(angle theta, distance magnitude) { /* impl */ }
};
当我尝试编译它时,我得到 "constructor cannot be redeclared"。但是(出于某种原因我无法弄清楚)当我在我的实际应用程序代码库中执行此操作时,class 会编译,但后来我在执行以下操作时得到 "call to constructor of 'Velocity' is ambiguous":
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) { }
};
但是如果我用相同的类型实例化它们,我会得到 "multiple overloads of 'Velocity' instantiate to the same signature 'void (float, float)'"。即使这可行,它仍然有点不令人满意,因为我必须在许多地方向 Velocity
类型添加模板参数。
typedef
不会创建新类型,它只是为具有不同名称并可能在不同命名空间中的类型创建别名,类似于 using
.
因此,您的两个构造函数实际上都是 float, float
。
如果您想创建一个实际的新类型,您可以创建一个新结构或 class 包含该类型。 C++ 计时类型,例如 std::chrono::seconds
包装一个整数。这样做还允许更具体的重载,例如您可能会说 displacement = velocity * time
,尽管这样做可能很快需要许多类型和运算符重载。
在重载float
和double
时也要小心,我当然不会这样做,以至于它们具有不同的含义。考虑像 0
和 1
这样的文字,或者像 int
.
是的,您需要不同的类型才能重载。
一种解决方案是通过更改函数名称避免重载。
另一种方法是通过创建 class
或 struct
包装浮点数来创建您的自定义类型。
然后您可以重载一些运算符以实现所需的行为,但在我看来,最好更改函数的名称
您可以围绕距离和角度创建一个非常轻量级的包装器,然后使用文字!
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};
}