Похоже, что libstdc++
правильно, это правильно, хотя мы увидим, что есть некоторые сомнения относительно того, является ли это дефектом в активной проблеме LWG 2192
.
В черновом стандартном разделе 26.8
[c.math] 11
раздела стандарта C++11 говорится:
При этом должны быть предусмотрены дополнительные перегрузки, достаточные для обеспечения:
и включает в себя следующий пункт:
- В противном случае, если какой-либо аргумент, соответствующий параметру double, имеет тип double или целочисленный тип, то все аргументы, соответствующие параметрам double, фактически преобразуются в тип double.
и мы видим, что это libstdc++
делает действительно предусмотреть для этого случай:
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }
Существует также отчет об ошибке gcc
std::abs (long long) прибегает к std ::abs (double), если llabs отсутствует, что ставит под сомнение правильность этой реализации, и в одном ответе говорится:
[...] соответствует стандарту, любое целое число должно безоговорочно становиться двойным. [...]
Отчет об ошибке в конечном итоге привел к активной проблеме LWG 2192: Действительность и возвращаемый тип std::abs(0u) неясны при подаче, что среди прочего говорит:
- В C++11 можно считать, что дополнительное правило «достаточной перегрузки» из 26.8 [c.math] p11 (см. также LWG 2086) применимо и к перегрузкам std::abs(), что может привести к следующему: возможные выводы:
Программа
#include <type_traits>
#include <cmath>
static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops");
int main() {
std::abs(0u); // Calls std::abs(double)
}
должен быть правильно сформирован из-за подпункта 2 ("[..] или целочисленный тип [..]") 26.8 [c.math] p11 (обратите внимание, что текущая резолюция LWG 2086 не исправить эту проблему).
- Любая единица перевода, включающая оба и может быть неправильно сформирована из-за двух конфликтующих требований к возвращаемому типу перегрузки std::abs(int).
Мне кажется, что по крайней мере второй исход не предполагается, лично я считаю, что оба неудачны [...] Также следует отметить, что соответствующий набор правил «функции универсального типа» из C99/C1x в 7.25 p2+ 3 ограничен функциями с плавающей запятой из и , поэтому его нельзя применять к функциям abs (но к функциям fabs!).
Вопрос в том, предназначалось ли это также для abs
. Это может быть дефектом, так как, похоже, нет способа интерпретировать текущую формулировку, чтобы исключить abs
.
Таким образом, текущая формулировка указывает на то, что libstdc++
соответствует, неясно, почему libc++
выбрала свою текущую реализацию такой, какая она есть. Я не могу найти ни отчетов об ошибках, ни дискуссий по этой теме, а в проблеме LWG не упоминаются расходящиеся реализации.
Предлагаемое решение сделает std::abs(0u)
неправильным:
Если abs() вызывается с аргументом целочисленного типа без знака, который не может быть преобразован в int путем целочисленного преобразования ([conv.prom]), программа имеет неверный формат. [Примечание: аргументы, которые могут быть преобразованы в int, разрешены для совместимости с C. — примечание в конце]
Хотя некоторые могут усомниться в использовании abs
с беззнаковым типом, Говард Хиннант указывает в отчете, что при использовании шаблонов такие последствия могут быть неочевидными, и приводит пример:
[...] особенно в C++, где у нас есть шаблоны, и задействованные типы не всегда очевидны для программиста во время разработки. Например, рассмотрим:
template <class Int>
Int
analyze(Int x, Int y)
{
// ...
if (std::abs(x - y) < threshold)
{
// ...
}
// ...
}
person
Shafik Yaghmour
schedule
20.04.2015