Как предотвратить неявное приведение типа double -> int? - PullRequest
19 голосов
/ 26 октября 2011

Вопрос, как указано выше, более подробно ниже:

У меня есть класс 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.

Редактировать: добавлены конструкторы для денег.

Редактировать: Спасибо всем за ваши ответы.Почти все они были замечательными и полезными.Комментарий Р. Мартиньо Фернандеса «Вы можете сделать inline const Money operator*( const Money & m, double d ) = delete;» был фактически ответом (как только я переключаюсь на компилятор с поддержкой C ++ 11).Kerrek SB дал хорошую альтернативу без C ++ 11, но в итоге я воспользовался подходом Nicola Musatti «overload long».Вот почему я отмечаю его ответ как «ответ» (также потому, что все полезные идеи появились в качестве комментариев к его ответу).Еще раз спасибо!

Ответы [ 4 ]

15 голосов
/ 26 октября 2011

Как насчет шаблона и проверки черты времени компиляции:

#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!");
  // ...
}
8 голосов
/ 26 октября 2011

Вы можете добавить объявление для частной перегрузки вашего расширенного оператора присваивания:

private:
  Money & operator*=( double i );
7 голосов
/ 26 октября 2011

Я могу придумать два способа обеспечить это:

  • , либо используя шаблон и "концептуальные" проверки
  • , либо используя "запрещенные" перегрузки

Использование перегрузок - решение 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) был двойным:

  • inкласс, объявите метод 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, если она у вас есть.Если вы этого не сделаете, то возврат к случаю шаблона, вероятно, является лучшим решением, потому что ошибки компилятора легче исправить, чем ошибки компоновщика.

0 голосов
/ 26 октября 2011

Вы можете создать тип держателя небольшого числа, который имеет все нужные вам свойства, а затем использовать его для взаимодействия с другими типами, такими как Money.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...