SFINAE std::isfinite и аналогичные функции, использующие std::is_arithmetic

Я только что столкнулся с ошибкой компиляции при переносе некоторого кода из VS2013 в GGC 4.9 и Clang 3.5 (используя libc++). Суть кода в том

#include <cmath>

struct Foo
{
    operator double() const { return( 101.0 ); } // Implicit conversion to double
};

int main( int, char** )
{
    Foo foo;

    std::exp( foo );      // Compiles
    std::isfinite( foo ); // Does not

    return( 0 );
}

Я считаю, что вызов isfinite не компилируется, потому что функция isfinite в cmath имеет возвращаемый тип, объявленный как:

typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type

и поскольку Foo не является is_arithmetic, isfinite удаляется из набора перегрузки. То же самое относится и к друзьям isfinite, таким как isnan. Поэтому мой вопрос заключается в том, ожидается ли это.

Требует ли стандарт, чтобы аргументы таких функций, как isfinite, на самом деле были прямо double или float, а не неявно конвертировались в них?

Также я немного не уверен, почему std::is_arithmetic не std::is_floating_point, разве is_arithmetic не означает isfinite для целых чисел?

В качестве дополнительного вопроса, как лучше всего указать ограничение, например is_convertible_to_floating_point?


person goneskiing    schedule 06.12.2014    source источник
comment
Поскольку C++11 std::exp также принимает целочисленные типы, а не только типы с плавающей запятой.   -  person Some programmer dude    schedule 07.12.2014
comment
И чтобы решить вашу проблему, вы можете легко добавить специализацию std::is_arithmetic для вашего учебный класс.   -  person Some programmer dude    schedule 07.12.2014
comment
@JoachimPileborg Нет, ты не можешь. Специализация признака стандартного библиотечного типа (кроме std::common_type) — UB.   -  person T.C.    schedule 07.12.2014
comment
Стандарт говорит, что должно быть три перегруженных подписи, принимающих float, double и long double соответственно. Я бы зарегистрировал ошибку.   -  person T.C.    schedule 07.12.2014


Ответы (1)


§26.8 [c.math]/p10-11:

Функции классификации/сравнения ведут себя так же, как макросы C с соответствующими именами, определенными в 7.12.3, Макросы классификации и 7.12.14, Макросы сравнения в стандарте C. Каждая функция перегружена для трех типов с плавающей запятой следующим образом:

// other functions omitted
bool isfinite(float x);

bool isfinite(double x);

bool isfinite(long double x);

При этом должны быть предусмотрены дополнительные перегрузки, достаточные для обеспечения:

  1. Если какой-либо арифметический аргумент, соответствующий параметру double, имеет тип long double, то все арифметические аргументы, соответствующие double параметрам, фактически преобразуются в long double.
  2. В противном случае, если какой-либо арифметический аргумент, соответствующий параметру double, имеет тип double или целочисленный тип, то все арифметические аргументы, соответствующие параметрам double, фактически преобразуются в double.
  3. В противном случае все арифметические аргументы, соответствующие double параметрам, имеют тип float.

Я бы зарегистрировал ошибку в libc++.

person T.C.    schedule 06.12.2014
comment
Просто отметим, что это относится и к GCC libstdС++. - person goneskiing; 07.12.2014
comment
@goneskiing Он отлично работает, когда я проверил libstdc++. - person T.C.; 07.12.2014
comment
Я использую GCC 4.9.1 (обычный пакет Ubuntu) в Ubuntu 14.10 с командной строкой gcc foo.cpp выдает ошибку: нет соответствующей функции для вызова 'isfinite (Foo&)' .... Вы используете 4.8, глядя на заголовок cmath кажется совсем другим. - person goneskiing; 07.12.2014
comment
Ах, gcc -std=c++11 foo.cpp работает. Кажется странным, что они не определяют enable_if, то есть предполагают, что опции -std не означают c++98, если вы просто выполняете gcc foo.cpp - person goneskiing; 07.12.2014
comment
Я только что обнаружил ошибку llvm.org/bugs/show_bug.cgi?id=18218 против libc++, в котором говорится именно об этой проблеме, поэтому в какой-то момент она должна быть исправлена - person goneskiing; 08.12.2014
comment
На самом деле Маршалл Клоу написал это marshall.calepin.co/doing-a -good-job-with-ltcmathgt.html по этому и многим другим вопросам реализации cmath - person goneskiing; 08.12.2014
comment
Да, это неприятная проблема, и у меня до сих пор нет хорошего решения. - person Marshall Clow; 09.12.2014