2013-02-11 8 views
6

Ho un codice di modello che funziona bene con Xcode 4.5 e LLVM 3.0, ma non riesce con la toolchain VS 2010 Express C++ (v 10.0.30319.1).C++ trasmette un valore in virgola mobile a un enum - ma non con VS 2010

Sto utilizzando un'API di terze parti di cui non ho il controllo. Esso fornisce i valori per il mio codice come 'blob' black-box che può essere interpretato solo da funzioni API:

// API_Secret is a black-box encapsulation of a floating-point number or a boolean value. 
// It is provided by a third-party API, with associated access functions. 
// For all intents and purposes, it's a complete black box. 
// This enum represents the internal 'type' of a secret value. 
enum API_SecretTypeEnum { 
    API_Number, 
    API_Boolean, 
}; 
// Other API declarations: 
API_SecretTypeEnum API_GetType(const API_Secret &value); 
double API_AsNumber(const API_Secret &value); 
bool API_AsBoolean(const API_Secret &value); 

// my code: 
template <typename ValueType> 
class Extractor { 
public: 
    ValueType extract(API_Secret value) { 
    if (API_GetType(value) == API_Number) { 
     return static_cast<ValueType>(API_AsNumber(value)); 
    } else if (API_GetType(value) == API_Boolean) { 
     return API_AsBoolean(value) ? ValueType(1) : ValueType(0); 
    } 
    return ValueType(); 
    } 
}; 

// boolean specialization - not 100% sure it's needed though 
template<> 
class Extractor <bool> { 
public: 
    bool extract(API_Secret value) { 
    return API_AsBoolean(value); 
    } 
}; 

Poi, più tardi:

API_Secret API_GetSomeValue(int some_sort_of_handle); 

// get some black-box values from the API 
API_Secret secret0 = API_GetSomeValue(0); 
API_Secret secret1 = API_GetSomeValue(1); 
API_Secret secret2 = API_GetSomeValue(2); 

// for certain external reasons we expect this to be an integer representation: 
Extractor<int> e0; 
int v0 = e0.extract(secret0); 

// for certain external reasons we expect this to be a double representation: 
Extractor<double> e1; 
double v1 = e1.extract(secret1); 

// for certain external reasons we expect this to be a boolean representation: 
Extractor<bool> e2; 
bool v2 = e2.extract(secret2); 

Ora, per la differenza tra Xcode, LLVM e VS 2010. In Xcode & LLVM, il seguente sarà la compilazione (come parte del programma completo):

enum MyEnum { 
    Enum0, 
    Enum1, 
}; 
Extractor<MyEnum> ee; 
MyEnum ve = ee.extract(secret0); 

Ie il modello di classe utilizza una conversione da static_cast a da un numero a virgola mobile a una enum. Questo sembra funzionare bene, e la sezione spiegazione this page suggerisce questo vale:

8) integer, virgola mobile, o il tipo di enumerazione può essere convertito in qualsiasi tipo di enumerazione (il risultato è specificato se la valore di espressione, convertito tipo sottostante del censimento, non è uno dei valori bersaglio enumerazione)

Tuttavia con VS2010, è stato rilevato il seguente errore di compilatore:

errore C2440: 'static_cast': non può convertire da 'doppio' a 'MyEnum'

 Conversions between enumeration and floating point values are no longer allowed 

E questo MSDN article sembra confermare questa non menzionando tipi a virgola mobile e affermando esplicitamente valore 'integrale':

L'operatore static_cast può convertire esplicitamente un valore integrale in un tipo di enumerazione. Se il valore del tipo integrale non rientra nell'intervallo dei valori di enumerazione, il valore di enumerazione risultante non è definito.

Quindi sembra che ci sia una differenza significativa qui tra VS 2010 e gli altri compilatori. Mi chiedo se questo è qualcosa che può essere aggirato in VS 2010? È una funzionalità più recente del linguaggio che VS 2010 semplicemente non supporta? Tuttavia, lo interrogo poiché il messaggio di errore indica "non più consentito", il che implica che è esplicitamente disabilitato.

Sono a conoscenza di una soluzione alternativa: invece di eseguire il casting su un enum (con Extractor<MyEnum>), posso invece utilizzare un Extractor<int> e quindi assegnarlo semplicemente alla variabile MyEnum di destinazione. Tuttavia questo template è effettivamente usato come parte di un sistema più grande che chiama funzioni avvolte, e in questo caso la funzione wrapped prende un valore MyEnum. Ciò impedisce al modello di corrispondere correttamente poiché il parametro ValueType viene effettivamente prelevato automaticamente dalla firma della funzione incapsulata.

In alternativa, è possibile scrivere una specializzazione di modello di Extractor che corrisponda solo ai tipi enum? Quindi posso eseguire prima il cast di un tipo integrale.O forse il modello base potrebbe sempre trasmettere a un int prima, quindi potrei scrivere una specializzazione in virgola mobile che non lo fa, ma non sono sicuro di come scrivere un modello che cattura tutti i tipi a virgola mobile (float, Doppio, ...).

+1

Errore di battitura nel codice di esempio: 'int v1 = e1.extract (secret1);' dovrebbe essere 'double v1 = e1.extract (secret1);' invece. –

+0

@JesseChisholm grazie, risolto. – meowsqueak

risposta

3

Sono abbastanza sicuro Visual Studio-2010 supports <type_traits>. È possibile utilizzare std::enable_if insieme a std::is_enum.

template <typename ValueType, typename Enable = void> 
class Extractor { 
public: 
    ValueType extract(API_Secret value); 
}; 

template <typename ValueType> 
class Extractor<ValueType, typename std::enable_if<std::is_enum<ValueType>::value>::type> 
{ 
... 
}; 


Si può fare lo stesso per abbinare galleggiante tipi di punti utilizzando std::is_floating_point.

+0

Grazie, sembra molto promettente. Dopo la specializzazione enum, come posso specificare il modello complementare, dove Enable è * not * enum? (cioè il modello originale). EDIT: oh, è semplice come std :: enable_if meowsqueak

+0

Così vicino ... funziona ovunque tranne che con la toolchain di Xcode - no , devi fare e poi ho un sacco di errori su std :: enable_if che deve essere __gnu_cxx :: __ enable_if - c'è un portatile modo per risolvere questo? Avrebbe senso usare invece le type_traits di boost? – meowsqueak

+0

Ho postato una domanda per affrontarlo direttamente qui - http://stackoverflow.com/questions/14823832 – meowsqueak

Problemi correlati