如何防止隐式转换加倍 - >诠释?

时间:2011-10-26 13:12:55

标签: c++ casting

上述问题,详情如下:

我有一个班级Money来处理......好吧,你猜对了。我非常严格禁止Moneydouble进行互动(*),因此以下代码可能:

Money m1( 4.50 );
double d = 1.5;
Money m2 = m1 * d; // <-- compiler error

现在我正在考虑允许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; }

工作正常, ...... 不幸的是,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”方法。这就是为什么我把他的答案标记为“答案”(也因为所有有用的想法都作为对他答案的评论)。再次,谢谢!

4 个答案:

答案 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_ifstatic_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