上述问题,详情如下:
我有一个班级Money
来处理......好吧,你猜对了。我非常严格禁止Money
和double
进行互动(*),因此以下代码不可能:
Money m1( 4.50 );
double d = 1.5;
Money m2 = m1 * d; // <-- compiler error
现在我正在考虑允许Money
与int
相乘,就像“你有6块蛋糕,每块4.50美元(所以去找一些更便宜的蛋糕)。”
class Money
{
Money();
Money( const Money & other );
explicit Money( double d );
...
Money & operator*=( int i );
...
}
inline const Money operator*( const Money & m, int i ) { return Money( m ) *= i; }
inline const Money operator*( int i, const Money & m ) { return Money( m ) *= i; }
工作正常,但 ......
不幸的是,C ++从double
到int
进行了隐式强制转换,所以突然我的第一个代码片段将被编译。我不希望这样。在这种情况下有没有办法阻止隐式演员?
谢谢! - 罗宾
(*)原因:我有很多遗留代码处理与Money
相关的所有double
相关内容,我不希望这些类型混淆,直到所有内容都与Money
一起运行
编辑:为Money添加了构造函数。
编辑:谢谢大家,感谢您的回答。几乎所有人都很棒,乐于助人。 R. Martinho Fernandes的评论“你能做inline const Money operator*( const Money & m, double d ) = delete;
”实际上就是答案(一旦切换到支持C ++ 11的编译器)。 Kerrek SB提供了一个很好的非C ++ 11选择,但我最终使用的实际上是Nicola Musatti的“重载long
”方法。这就是为什么我把他的答案标记为“答案”(也因为所有有用的想法都作为对他答案的评论)。再次,谢谢!
答案 0 :(得分:15)
模板加编译时特征检查如何:
#include <type_traits>
// ...
template <typename T>
Money & operator*=(const T & n)
{
static_assert(std::is_integral<T>::value, "Error: can only multiply money by integral amounts!");
// ...
}
答案 1 :(得分:8)
您可以为扩充赋值运算符的私有重载添加声明:
private:
Money & operator*=( double i );
答案 2 :(得分:7)
我可以想出两种方法来提供这个:
使用重载是C ++ 11解决方案。 C ++ 11特别针对您的情况引入了delete
关键字!
Money& operator*=(int i);
Money& operator*=(float f) = delete;
Money operator*(Money m, int i) { return m*i; }
Money operator*(Money m, float f) = delete;
Money operator*(int i, Money m) { return m*i; }
Money operator*(float f, Money m) = delete;
旧的方式(C ++ 03)是双重的:
private
第二个是类方法案例中的安全措施,也是自由方法案例中的唯一方法。令人遗憾的是,它仅在链接时被检测到......并且delete
关键字更好;)
使用模板是另一种解决方案。您可以使用std::enable_if
或static_assert
:一个将从重载集(SFINAE)中删除该函数,而另一个将使实例化失败(编译器错误)。
示例:
// For enable_if
template <typename T>
std::enable_if<std::is_integral<T>::value, Money&> operator*=(T t);
template <typename T>
std::enable_if<std::is_integral<T>::value, Money> operator*(Money m, T t);
template <typename T>
std::enable_if<std::is_integral<T>::value, Money> operator*(T t, Money m);
static_assert
的例子更自然(它就像常规断言一样)。
如果你拥有它,我宁愿推荐重载+ delete
。如果不这样做,那么回退到模板案例可能是最好的解决方案,因为它比链接器更容易纠正编译器错误。
答案 3 :(得分:0)
您可以创建一个包含所需属性的小号持有者类型,然后使用它来与其他类型进行交互,例如Money
。