如何防止隐式转换double - > int?

Rob*_*bin 19 c++ casting

问题如上,更多详情如下:

我有一堂课Money要处理......好吧,你猜对了.我非常严格,不允许Moneydouble互动(*),所以下面的代码是没有可能的:

Money m1( 4.50 );
double d = 1.5;
Money m2 = m1 * d; // <-- compiler error
Run Code Online (Sandbox Code Playgroud)

现在我想允许乘Moneyint,如"你有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; }
Run Code Online (Sandbox Code Playgroud)

这工作正常,但是 ...不幸的是,C++不隐式转换doubleint,如此突然我的第一个代码段编译.我不希望这样.在这种情况下有没有办法防止隐式演员

谢谢! - 罗宾

(*)原因:我有很多遗留代码处理所有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"方法.这就是为什么我将他的答案标记为"答案"(也因为所有有用的想法都作为对他答案的评论).再次,谢谢!

Ker*_* SB 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!");
  // ...
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*tti 8

您可以为扩充赋值运算符的私有重载添加声明:

private:
  Money & operator*=( double i );
Run Code Online (Sandbox Code Playgroud)

  • @Robin:在C++ 11中你可以做`inline const Money operator*(const Money&m,double d)= delete;`.如果您的编译器支持此功能,请使用它! (5认同)
  • 或者甚至使用`is_same`或`is_integral`检查使其成为模板! (2认同)

Mat*_* M. 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;
Run Code Online (Sandbox Code Playgroud)

旧的方式(C++ 03)去了两倍:

  • 在类中,声明方法 private
  • 不要定义方法并等待链接器抱怨

第二个是类方法案例中的安全措施,也是自由方法案例中的唯一方法.令人遗憾的是,它仅在链接时被检测到...并且delete关键字更好;)


使用模板是另一种解决方案 您可以使用std::enable_if或者static_assert:one将从重载集(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);
Run Code Online (Sandbox Code Playgroud)

这些例子static_assert更自然(它就像常规断言一样).


delete如果你有,我宁愿推荐重载+ .如果不这样做,那么回退到模板案例可能是最好的解决方案,因为它比链接器更容易纠正编译器错误.