Ответ 1
Вы можете добавить объявление для личной перегрузки вашего расширенного оператора присваивания:
private:
Money & operator*=( double i );
Вопрос, как указано выше, более подробно ниже:
У меня есть класс 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; }
Это прекрасно работает, , но.
К сожалению, С++ делает неявные отбрасывания от double
до int
, поэтому мой первый фрагмент кода будет скомпилирован. Я не хочу этого. Есть ли способ предотвратить неявные приведения в этой ситуации?
Спасибо! - Робин
(*) Причина: у меня много устаревшего кода, который обрабатывает все Money
-связанные вещи с помощью double
, и я не хочу, чтобы эти типы путались до тех пор, пока все не будет запущено с Money
.
Изменить: добавлены конструкторы для денег.
Изменить: Спасибо, всем, за ваши ответы. Почти все они были большими и полезными. Комментарий R. Martinho Fernandes "вы можете сделать inline const Money operator*( const Money & m, double d ) = delete;
" на самом деле был ответом (как только я переключусь на поддерживающий С++ 11 компилятор). Kerrek SB дал хорошую альтернативу не-С++ 11, но то, что я в конечном итоге использовал, - это подход Николаса Мусатти "перегрузка long
". Вот почему я отмечаю его ответ как "ответ" (также потому, что все полезные идеи появились в виде комментариев к его ответу). Еще раз спасибо!
Вы можете добавить объявление для личной перегрузки вашего расширенного оператора присваивания:
private:
Money & operator*=( double i );
Как насчет проверки шаблона плюс времени компиляции:
#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!");
// ...
}
Я могу представить два способа обеспечить это:
Использование перегрузок - это решение С++ 11. С++ 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;
Старый способ (С++ 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
, если она у вас есть. Если вы этого не сделаете, то резервное копирование в случае с шаблоном, вероятно, является лучшим решением, поскольку легче исправить ошибки компилятора, чем ссылки.
вы можете создать небольшой тип держателя номера, который имел все необходимые свойства, а затем использовать его для взаимодействия с другими типами, например Money
.