2010-09-27 19 views
11

sezione 4.3 della C++ Templates stati 'Non essendo in grado di utilizzare letterali in virgola mobile (e semplici espressioni a virgola mobile costanti) come argomenti template ha storici ragioni.'specializzazione del modello con galleggiante come non tipo

Allo stesso modo,

$ 14,1/7 membri - "Un non-tipo modello-parametro non deve essere dichiarato di avere in virgola mobile, classe o tipo void [Esempio:

.
template<double d> class X; // error 
template<double* pd> class Y; // OK 
template<double& rd> class Z; // OK" 
  1. Qual è la ragione storica che è bein g parlato nel libro nella citazione di cui sopra?

  2. Guardando al motivo per cui Y e Z sono validi ma non X, l'intera sfida relativa all'utilizzo di parametri di tipo non tipo di tipo floating non ha nulla a che fare con i puntatori/riferimenti?

  3. Perché i parametri di tipo non di tipo non possono essere di tipo classe?

+0

@aaa carpa: Sì, potrei capirlo. Sono curioso di sapere quale sia la ragione storica per cui non si possono distinguere i tipi in virgola mobile. Sto anche cercando di capire perché X non è formato da Y o Z. – Chubsdad

+0

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/2f4c0b5a5ae627bc/bbe916d9e75426de?hl=it&ie=UTF -8 & oe = utf-8 & q = virgola mobile + letterali +% 28as + modello + argomenti + storico + motivi & pli = 1 – Anycorn

+0

@aaa carpa: no, non lo è. L'indirizzo passato sarebbe noto solo al linker, ma il compilatore ha già bisogno di istanziare. – MSalters

risposta

5

numeri a virgola mobile non sono rappresentate universale (e alcuni valori non possono anche essere rappresentati senza perdite di precisione dalla sua base di approssimazione) e pertanto possono essere diversi da una piattaforma all'altra provocando lo stesso codice C++ generare modelli differenti su diverse piattaforme.

(si può dire come C++ supporta compilazione cross senza richiedere il compilatore di emulare completamente l'aritmetica in virgola mobile della macchina di destinazione. Permettere float o doppio come parametro di template da inficiare questa.)

template<float F> 
float squared_float() 
{ 
return F * F; 
} 

Ad esempio, squared_float < 1.0> potrebbe essere la stessa funzione di squared_float < 1.00000001> su alcune implementazioni, mentre su altri sarebbero due funzioni diverse.


A reference to a float significa che il compilatore può ottimizzarlo in quanto conosce il suo valore e che non dovrebbe mai cambiare.

Per pointer, è semplicemente un altro tipo di dati (a 32 bit/64 bit) dipendente dall'architettura che non ha nulla a che fare con float.

+0

Su una determinata piattaforma, tuttavia, questo non dovrebbe essere un problema. Può tuttavia influire sulla portabilità, il che è vero per molte altre funzionalità nella lingua, ad es. sizeof (int) – Chubsdad

10

Potrebbe essere difficile scegliere l'istanza di modello giusta, a causa di possibili errori di arrotondamento.

Si consideri il seguente:

template<float n> 
void f(n) {...} //Version 1 

template<0.3333> 
void f() { ...} // Version 2:Specialization for 0.3333 

f(1/3); -> Quale versione sarebbe stato chiamato?

Si consideri il seguente codice:?

template <float f> class foo { ... }; 
foo<1E6 + 1E-6> my_foo; 

"Quello che dovrebbe generare il compilatore Il compilatore deve conoscere i dettagli della destinazione architettura in virgola mobile per essere in grado di eseguire un'istanza del modello Questo è. abbastanza facile se il compilatore è in esecuzione sull'architettura target , può solo fare il calcolo e trovare la risposta, ma se si esegue la compilazione incrociata, il compilatore dovrebbe essere in grado di sintetizzare il comportamento in virgola mobile di ogni architettura di destinazione prevista e per fortuna il Comitato per gli standard ha deciso che sarebbe stato irragionevole. "

spudoratamente copiato da here.

Perché parametri di modello non di tipo non possono essere di tipo di classe

Come per la mia comprensione un non-tipo paramater non può essere di tipo di classe perché potrebbe esserci più di un'implementazione di una classe, ad esempio

template <typename T> 
class demo{...}; 

template <>  
class demo<int>{...}; 


template <typename T, demo d> //which demo?? demo<T> or demo<int> 
class Example{...}; 

Le classi locali non possono essere utilizzate come parametri modello perché they don't have external linkage.

+0

0.3333 è di tipo "double", non è identico al tipo di 1/3? Quindi il compilatore può scegliere la specializzazione per "double" con default come <0.3333> – Chubsdad

+0

che suona ragionevole, la IEEE repr è stata introdotta nel 1985, nello stesso momento in cui il C++ è diventato "ufficiale", quindi forse non c'era la matematica standard per virgola mobile – Anycorn

+1

@Chubsdad : Consulta [questo] (http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/a7e278eeb134072c/e8f65e0d90cadf7e?lnk=gst&q=floating+point+literals+come+template+arguments# e8f65e0d90cadf7e) comp.lang.C++ thread –

1

L'esatta codifica dei valori in virgola mobile è più soggetta a stranezze di singole CPU. Ad esempio, nella valutazione di un'espressione apparentemente costante, una CPU dovrebbe utilizzare registri CPU 80bit di precisione più elevata e solo alla fine tornerà a 64 bit? Se un compilatore dice sì e un altro no, il modello otterrà due distinte istanze. Ma alcuni altri compilatori potrebbero avere solo registri a 64 bit e forse CPU diverse potrebbero variare a seconda del valore di epsilon. L'ordine in cui un compilatore sceglie di valutare un'espressione, o se una libreria è stata compilata usando una libreria di emulazione a virgola mobile, ecc. Potrebbe causare tali mis-match. Inoltre, i numeri in virgola mobile hanno alcuni casi di bordo strani: positivi e negativi 0 ecc., Per i quali dovrebbe essere definito il comportamento.

Questi problemi possono potenzialmente mordere in ambienti in cui gli oggetti sono compilati su macchine diverse (con diverse CPU, versioni del compilatore e flag, ecc.), Ma devono collegarsi in modo affidabile. Le aziende di solito fanno questo, e anche le librerie distribuite in binario affrontano tali problemi. I compilatori C++ in genere cercano di adottare alcuni Application Binary Interface (ABI) che siano il più coerenti possibile tra versioni e ambienti, ma attualmente non standardizzerebbero come venivano calcolati i parametri in virgola mobile, e non è ovvio come potrebbero, ad es. mi aspetto che tutti i compilatori utilizzino la stessa emulazione in virgola mobile del software per ricavare i valori. Ciò richiederebbe uno sforzo di coordinamento e le soluzioni di emulazione esistenti potrebbero avere problemi di licenza.

È interessante notare che Walter Bright (di Digital Mars) ha pensato che fosse tutto schifoso e consentisse costanti in virgola mobile in D ... Immagino che abbia avuto un'esperienza del mondo reale delle conseguenze che sarebbero state utili alla comunità C++, ma io non ho sentito recentemente.

+0

ci sono alcune cose MPL in boost vault che consentono costanti FP. – Anycorn

+0

hmmm ... Evito MPL - il fastidioso boost ha rifiutato di ospitare Loki mentre i documenti online disponibili per MPL sono i peggiori di tutta la raccolta di boost e IMHO è sfacciata "Farò un po 'di soldi qui perché ho il controllo di incrementare "la pubblicità per i libri, mentre altri autori di boost dovrebbero effettivamente vivere dal generale" condividilo liberamente con la comunità ". L'entusiasmo spinge a sposare pubblicamente lo –

+0

[Potremmo chiederglielo] (http://stackoverflow.com/users/ 33949/walter-bright) –

1

Una soluzione a questo problema consiste nell'utilizzare numeri razionali. Inviare due interi parametri non-type e quindi inizializzare il galleggiante nel costruttore come segue

template<int dNum =1, int dDen = 3> 
class myclass { 
    double d; 
    myclass: d(dNum/dDen) {} 
}; 

voilà, passando un float.

+0

Se si utilizza C++ 11, 'std :: ratio' funziona bene per questo. – Ponkadoodle

+0

Ma come si trasforma lo std :: ratio in un float? – Ant6n

0

Una possibile soluzione a questo problema consiste nell'utilizzare un tipo con valore costante che è float, quindi utilizzare tale tipo come parametro del modello. Per esempio, se si vuole avere un polinomio intero, per esempio, e si vuole valutare ad un certo valore del punto in fase di compilazione flottante:

template <int a, int b, int c> 
class Polynomial { 
public: 
    template <typename t> 
    static constexpr float eval() { 
     return a*t::value*t::value + b*t::value + c; 
    } 
}; 

class THREE_POINT_FIVE { 
public: 
    static constexpr float value = 3.5f; 
}; 

int main() { 
    constexpr float y = Polynomial<2, 0, 1>::typename eval<THREE_POINT_FIVE>(); 
    std::cout << y << std::endl; 
} 

si potrebbe anche utilizzare classi di supporto che permettono di creare classi di carri allegorici, per esempio per percentuale:

template <unsigned int p> 
class PERCENT { 
public: 
    static constexpr float value = p * 0.01f; 
}; 

... 
constexpr float y2 = Polynomial<2, 0, 1>::typename eval<PERCENT<43>> 
... 

Immagino che questo sia simile all'utilizzo dello std::ratio menzionato prima.

Problemi correlati