Я столкнулся с несколькими различными примерами способов, с помощью которых 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двусмысленным
- Передайте gcc
Уловка:
namespace neveruse{
int abs(int);
}
using namespace neveruse;
Вопрос: Есть ли причина предпочесть одно из решений для выпуска 3 над другим? Устанавливает ли какое-либо из этих исправлений другие потенциальные проблемы, которые мне необходимо соблюдать?