2014-12-06 23 views
5

Po prostu napotkałem awarię kompilacji podczas przenoszenia kodu z VS2013 do GGC 4.9 i Clang 3.5 (używając libC++). Istota kod jestSFNAE std :: isfinite i podobne funkcje używające std :: is_arithmetic

#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); 
} 

wierzę wywołanie isfinite nie kompiluje ponieważ isfinite funtion w cmath ma Zwraca typ zadeklarowany jako:

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

i dlatego Foo nie jest is_arithmetic, isfinite zostanie usunięty z zestawu przeciążeniowego. To samo dotyczy znajomych isfinite, takich jak isnan. Więc moje pytanie brzmi, czy to jest oczekiwane.

Czy standard wymaga, aby argumenty dla funkcji takich jak isfinite były faktycznie bezpośrednio double lub float, a nie były domyślnie dla nich wymienialne?

Również nie jestem pewien, dlaczego jest std::is_arithmetic nie std::is_floating_point, czy is_arithmetic implikuje isfinite na liczbach całkowitych?

Jako dodatkowe pytanie, jaki jest najlepszy sposób określenia ograniczenia takiego jak is_convertible_to_floating_point?

+1

Ponieważ C++ 11 ['std :: exp'] (http://en.cppreference.com/w/cpp/numeric/math/exp) również przyjmuje typy integralne, nie tylko typy zmiennoprzecinkowe. –

+0

I aby rozwiązać twój problem, możesz łatwo dodać specjalizację ['std :: is_arithmetic'] (http://en.cppreference.com/w/cpp/types/is_arithmetic) dla twojej klasy. –

+2

@JoachimPileborg Nie, nie możesz. Specjalizacją standardowej cechy typu biblioteki (z wyjątkiem 'std :: common_type') jest UB. –

Odpowiedz

5

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

The classification/comparison functions behave the same as the C macros with the corresponding names defined in 7.12.3, Classification macros, and 7.12.14, Comparison macros in the C Standard. Each function is overloaded for the three floating-point types, as follows:

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

bool isfinite(double x); 

bool isfinite(long double x); 

Moreover, there shall be additional overloads sufficient to ensure:

  1. If any arithmetic argument corresponding to a double parameter has type long double , then all arithmetic arguments corresponding to double parameters are effectively cast to long double .
  2. Otherwise, if any arithmetic argument corresponding to a double parameter has type double or an integer type, then all arithmetic arguments corresponding to double parameters are effectively cast to double .
  3. Otherwise, all arithmetic arguments corresponding to double parameters have type float .

Chciałbym zgłosić błąd przeciwko libC++.

+0

Zauważ, że dotyczy to również GCC libstdC++ oraz – goneskiing

+0

@goneskiing Działa to dobrze, gdy [testowałem na libstdC++] (http://coliru.stacked-crooked.com/a/cb0d355028099712). –

+0

Używam GCC 4.9.1 (normalny pakiet Ubuntu) na Ubuntu 14.10 z linii poleceń "gcc foo.cpp" daje "błąd: brak pasującej funkcji dla wywołania" isfinite (Foo &) "...". Czy używasz 4.8, patrząc na nagłówek cmath, wydaje się całkiem inny. – goneskiing

Powiązane problemy