Как я могу избежать неожиданных результатов из std :: abs?
Я столкнулся с несколькими различными примерами способов, с помощью которых std::abs
может дать неожиданные результаты:
- Этот вопрос (В функции std :: abs) указывает, что
<cstdlib>
обеспечивает перегрузки для интегральных типов, в то время как <cmath>
обеспечивает перегрузки для типов с плавающей точкой. Неспособность включить правильный заголовок дает неопределенное поведение, которое компилятору разрешено молча принимать - C++ Отчет о дефектах 2735 указывает на то, что стандартам C++ 11 и C++ 14 технически требуется, чтобы
std::abs(short)
возвращал double
, хотя большинство компиляторов игнорируют соответствующую формулировку и возвращают int
. Решение этой проблемы указывает, что в C++ 17 была изменена формулировка, так что std::abs(short)
возвращает int
- Ответы на этот вопрос (когда я использую fabs и когда достаточно использовать std :: abs?), Обратите внимание, что использование
std::abs
может привести к ошибкам, затрудняющим поиск, поскольку (в современных C++ ) заголовкам, которые вводят std::abs
, разрешено вводить глобальную abs
функцию (которая может иметь или не иметь одинаковые перегрузки), и легко случайно использовать abs
вместо std::abs
Исправления, о которых я знаю, являются:
- Избегайте неопределенного поведения:
<cstdlib>
если оцениваете std::abs([integral type])
и <cmath>
если оцениваете std::abs([floating point type])
- Два варианта:
- Используйте C++ 17 или pre- (C++ 11)
- Обходитесь с тем, что
std::abs(short)
может возвращать int
или double
зависимости от соответствия компилятора стандарту C++ 11/C++ 14
- Два варианта:
- Передайте gcc
–Wconversion
чтобы вызовы типа abs(2.0)
вызывают предупреждение при компиляции - Используйте трюк (адаптированный из nm ответ на (отключить math.h дерьмо при работе с cmath)), чтобы сделать глобальный
abs
двусмысленным
Уловка:
namespace neveruse{
int abs(int);
}
using namespace neveruse;
Вопрос: Есть ли причина предпочесть одно из решений для выпуска 3 над другим? Устанавливает ли какое-либо из этих исправлений другие потенциальные проблемы, которые мне необходимо соблюдать?
Ответы
Ответ 1
Создайте собственный файл заголовка, который определяет inline
функцию absolute
которая, в свою очередь, включает все правильные заголовки и исправляет ошибки с возвращаемыми типами и вызывает std::abs
.
Затем не используйте abs
или std::abs
(или любой токен с именем abs
). Обеспечьте это в git commit (или любой другой системе управления версиями, которую вы используете), кроме как в этом файле.