Как я могу избежать неожиданных результатов из std :: abs?

Я столкнулся с несколькими различными примерами способов, с помощью которых std::abs может дать неожиданные результаты:

  1. Этот вопрос (В функции std :: abs) указывает, что <cstdlib> обеспечивает перегрузки для интегральных типов, в то время как <cmath> обеспечивает перегрузки для типов с плавающей точкой. Неспособность включить правильный заголовок дает неопределенное поведение, которое компилятору разрешено молча принимать
  2. C++ Отчет о дефектах 2735 указывает на то, что стандартам C++ 11 и C++ 14 технически требуется, чтобы std::abs(short) возвращал double, хотя большинство компиляторов игнорируют соответствующую формулировку и возвращают int. Решение этой проблемы указывает, что в C++ 17 была изменена формулировка, так что std::abs(short) возвращает int
  3. Ответы на этот вопрос (когда я использую fabs и когда достаточно использовать std :: abs?), Обратите внимание, что использование std::abs может привести к ошибкам, затрудняющим поиск, поскольку (в современных C++ ) заголовкам, которые вводят std::abs, разрешено вводить глобальную abs функцию (которая может иметь или не иметь одинаковые перегрузки), и легко случайно использовать abs вместо std::abs

Исправления, о которых я знаю, являются:

  1. Избегайте неопределенного поведения: <cstdlib> если оцениваете std::abs([integral type]) и <cmath> если оцениваете std::abs([floating point type])
  2. Два варианта:
    • Используйте C++ 17 или pre- (C++ 11)
    • Обходитесь с тем, что std::abs(short) может возвращать int или double зависимости от соответствия компилятора стандарту C++ 11/C++ 14
  3. Два варианта:
    • Передайте 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 (или любой другой системе управления версиями, которую вы используете), кроме как в этом файле.