В принципе, если я хочу что-то подобное,
double b = sin(2.2);
но случайно напишу что-то вроде этого,
double b = sin(2.2f);
нет сообщения об ошибке или даже предупреждения, даже если это явно приводит к другому, неточному и, следовательно, неверному результату. Этот тип ошибки можно предотвратить, если заставить компилятор не делать никаких неявных преобразований типа float в double. Есть ли способ достичь этого, будь то с помощью переключателя компиляции (предпочтительно в Visual Studio), некоторых интеллектуальных макросов или класса, который ведет себя как переменные типа float / double и объявляет свои собственные операторы?
Изменить: я также заинтересован в решении аналогичных проблем с использованием операторов (например, double b = 2.2f * 2.2f) или присваивания (double b = 2,2f).
Вы можете использовать type_assert
полезность.
Пример:
#include <cmath>
#include <type_traits>
template<typename T, typename U>
const U& type_assert(const U& u) {
static_assert(std::is_same<T, U>::value, "...");
return u;
}
int main() {
double t = type_assert<double>(std::sin(2.2f));
}
Если ожидаемый тип отличается, он выдаст ошибку компилятора. Скорее всего, компилятор может оптимизировать это, если он пройдет, по крайней мере, в моем случае с -O3
,
Вы можете сделать вызов sin(float)
неоднозначный, определяя что-то вроде
double sin(float x) { abort(); }
Тогда звонки sin
на float
даст вам ошибку во время компиляции. Это работает, потому что в cmath
заголовок, std::sin
перегружена функция с float sin(float)
, double sin(double)
, а также long double sin(long double)
варианты. Компилятор не может знать, хотел ли ты ::sin(float)
или же std::sin(float)
, поэтому он вскидывает руки в замешательстве.
Я бы не рекомендовал оставлять подобные вещи в своей кодовой базе, но это может быть полезно, если вы пытаетесь найти все случаи ошибок, подобных этой, и исправить их.
Что-то вроде того?
class MyDouble{
public:
MyDouble(float _f) {throw "only use double!";}
MyDouble(double _d) : m_data(_d) {}
operator float() const {throw "conversion to float occurred!";}
operator double() const {return m_data;}
private:
double m_data;
};
но да, вам придется начать использовать этот класс в своих вызовах математических функций, что делает его очень уродливым:
MyDouble d(3.2);
sin(d);
// or...
cos(MyDouble(2.3));
ОБНОВИТЬ — Пример реализации оператора (бинарный оператор, поскольку унарный должен быть частью класса):
MyDouble operator+(const & MyDouble _lhs, const & MyDouble _rhs){
MyDouble rez(_lhs);
rez += _rhs;
return rez;
}
Конечно, вам не нужно реализовывать это таким образом (используя ярлык operator+=
) но это делает код легче поддерживать
Я только что понял, что вы используете Microsoft продукт, но я оставлю этот ответ, так как он может помочь кому-то еще.
Вы смотрели через переключатели компилятора? Я предполагаю, что есть подобный вариант.
О, МОЙ БОГ! Я только что искал помощь с опциями и предупреждениями Visual Studio! (ссылка на сайт)
я ТАК извиняюсь! Я не знал! Это один из наименее полезные списки опций и переключателей, которые я когда-либо видел! Еще более иронично, они начали собирать StackOverflow для получения ответов и ссылок здесь.
Но я нашел некоторые подсказки:
Предупреждение компилятора (уровни 3 и 4) C4244 —
преобразование ‘преобразование из’ type1 ‘в’ type2 ‘, возможная потеря данных
Используется таким образом:
// Enable this to find unintended double to float conversions.
// warning C4244: 'initializing' : conversion from 'double' to 'float', possible loss of data
#pragma warning(3 : 4244)
GCC / G ++ переключатели (
Почему бы не позволить компилятору сообщить вам, когда вы случайно это сделаете?
Со страницы руководства g ++ / gcc:
-Wdouble-promotion (C, C++, Objective-C and Objective-C++ only)
* Give a warning when a value of type "float" is implicitly promoted to "double".
... some verbage clipped ...
* It is easy to accidentally do computations with "double" because floating-point
literals are implicitly of type "double".
Добавление -Wdouble-promotion
на ваш CXXFLAGS
должен предоставить вам предупреждения во время компиляции.
Существует также -fsingle-precision-constant
который запрещает неявное преобразование чисел с плавающей точкой в двойники.