2014-12-06 15 views
5

Ho appena eseguito un errore di compilazione durante il porting di codice da VS2013 a GGC 4.9 e Clang 3.5 (utilizzando libC++). Il nocciolo del codice èSFINAE std :: isfinite e funzioni simili utilizzando 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); 
} 

Credo che la chiamata isfinite non viene compilato perché il isfinite funtion in cmath ha tipo restituito dichiarato come:

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

e perché Foo non è is_arithmetic, isfinite viene rimosso dal set di sovraccarico. Lo stesso vale per gli amici di isfinite come isnan. Quindi la mia domanda è se questo è previsto.

Lo standard richiede che gli argomenti per funzioni come isfinite come effettivamente direttamente double o float anziché essere implicitamente convertibili a loro?

Anche io sono un po 'incerto il motivo per cui è std::is_arithmetic non std::is_floating_point, non implica is_arithmeticisfinite su interi?

Come domanda aggiuntiva qual è il modo migliore per specificare un vincolo come is_convertible_to_floating_point?

+1

Poiché C++ 11 ['std :: exp'] (http://en.cppreference.com/w/cpp/numeric/math/exp) accetta anche tipi interi, non solo i tipi a virgola mobile. –

+0

E per risolvere il tuo problema, puoi facilmente aggiungere una specializzazione di ['std :: is_arithmetic'] (http://en.cppreference.com/w/cpp/types/is_arithmetic) per la tua classe. –

+2

@JoachimPileborg No non puoi. Specializzare un tratto di tipo libreria standard (eccetto 'std :: common_type') è UB. –

risposta

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 .

mi piacerebbe aprire un bug contro libC++.

+0

Giusto notare che questo vale anche per GCC libstdC++ – goneskiing

+0

@goneskiing Funziona bene quando io [testato contro libstdC++] (http://coliru.stacked-crooked.com/a/cb0d355028099712). –

+0

Sto usando GCC 4.9.1 (pacchetto Ubuntu normale) su Ubuntu 14.10 con la riga di comando "gcc foo.cpp" restituisce "errore: nessuna funzione di matching per la chiamata a 'isfinite (Foo &)' ...". Stai usando 4.8, guardando l'header cmath sembra abbastanza diverso. – goneskiing

Problemi correlati