2013-07-18 12 views
11

W roku 2003 - tak, - Vandervoorde i Josuttis napisał w swojej książce "C++ Szablony" (str. 40):Dlaczego podwójny niedozwolony jest parametrem szablonu innego niż typ?

Nie będąc w stanie używać literały zmiennoprzecinkowe (i prosty stały o zmiennym wyrażenia punktowe), ponieważ argumenty szablonu mają przyczyny historyczne. Ponieważ nie ma poważnych wyzwań technicznych, może to być obsługiwane w przyszłych wersjach C++.

Ale to nadal nie działa, nawet w C++ 11:

template<double D> //error 
void foo() {} 

Dlaczego nie dodaje?

+11

Biorąc pod uwagę, że równość zmiennoprzecinkowa jest śliskie nie wiem, jak mogli powiedzieć "nie ma poważnych technicznych wyzwań". Sądzę, że byłoby to najeżone niebezpieczeństwem. –

+0

@ ErnestFriedman-Hill: To wydaje się być podstawą odpowiedzi na moje pytanie. –

+0

Jednak regularnie zajmujemy się kwestiami równości w kodzie wykonawczym. Te same zastrzeżenia dotyczyłyby ich użycia w szablonach ... Naprawdę nie widzę dobrego powodu, aby utrzymywać je tylko w środowisku wykonawczym. –

Odpowiedz

10

Zawsze zakładałem, że miało to związek z odpowiednimi implementacjami względem siebie. Jak te dwa przypadki są takie same lub różne:

template class foo<10./3.> 
template class foo<1./3 * 10.> 

Oni nie mogą generować taką samą reprezentację podwójnej precyzji, więc kompilator może myśleć o nich jak o różnych klas. Wtedy nie można ich przypisać do siebie itp.

5

Podczas używania liczb zmiennoprzecinkowych istnieje wiele problemów z zaokrąglaniem i równością. Z punktu widzenia komitetu normalizacyjnego należy upewnić się, że dwa programy wykonują to samo na kilku kompilatorach. Dlatego musisz dokładnie określić, co jest wynikiem operacji zmiennoprzecinkowej. Prawdopodobnie uważali, że norma IEEE-754 nie jest wystarczająco precyzyjna ...

Nie chodzi więc o to, czy można ją wdrożyć, ale o to, jakie dokładnie zachowanie chcemy mieć.

Pamiętaj jednak, że constexpr przyjmuje wartości zmiennoprzecinkowe. Zazwyczaj wystarcza to do obliczenia czasu kompilacji.

7

Spójrzmy na poniższy kod:

template<double D> int f(){ 
    static int i=0; 
    ++i; 
    return i; 
} 

... 

#define D1=... 
#define D2=... 
cout << f<D1>()<<endl; // returns 1 
cout << f<D1-D2+D2>()<<endl; // may return 1 or 2, depending on many things 

See, D1-D2+D2 może być równa D1 dla pewnych wartości, ale nie jest równe dla innych.

ważniejsze - mogą być równe lub nie w zależności od zaokrąglania ustawień

I wreszcie, mogą być równe lub nie w zależności od kompilatory/architektur/wiele innych rzeczy.

Chodzi o to, operacji zmiennoprzecinkowych nie są wystarczająco dobrze zdefiniowane do użycia szablonów (są dobrze zdefiniowane, ale istnieje wiele możliwych wariancji w zależności od różnych opcji)

+0

"zależne od ustawień" nie jest powodem. 'sizeof (Foo)' może również zależeć od ustawień, ale jest jednoznacznie dozwolone. – MSalters

+1

Tak, ale ustawienia dla 'sizeof' oceniają w czasie kompilacji, a szablony są również oceniane podczas kompilacji. Ustawienia zaokrąglania mogą się zmieniać w czasie wykonywania. Prowadzi to do przypadku, w którym dwie zmienne są dokładnie równe (z określonymi ustawieniami zaokrąglania w czasie wykonywania), ale ich odpowiednie szablony są różne (ponieważ utworzone obliczenia spowodowały różne wartości w czasie kompilacji). W moim przykładzie, jeśli obliczyłeś 'D1-D2 + D2' w czasie wykonywania, możesz uzyskać dokładnie' D1', ale szablony są wciąż oceniane na różne funkcje. – rabensky

+0

Twój przykład wydaje się dziwny. "Może wrócić 1 lub 2". Jednak D nie jest nawet używane w funkcji. czego mi brakuje? –

Powiązane problemy