Kiedy próbuję użyć float
jako parametru szablonu, kompilator woła o ten kod, podczas gdy int
działa dobrze.
Czy to dlatego, że nie mogę użyć float
jako parametru szablonu?
#include<iostream>
using namespace std;
template <class T, T defaultValue>
class GenericClass
{
private:
T value;
public:
GenericClass()
{
value = defaultValue;
}
T returnVal()
{
return value;
}
};
int main()
{
GenericClass <int, 10> gcInteger;
GenericClass < float, 4.6f> gcFlaot;
cout << "\n sum of integer is "<<gcInteger.returnVal();
cout << "\n sum of float is "<<gcFlaot.returnVal();
return 0;
}
Błąd:
main.cpp: In function `int main()':
main.cpp:25: error: `float' is not a valid type for a template constant parameter
main.cpp:25: error: invalid type in declaration before ';' token
main.cpp:28: error: request for member `returnVal' in `gcFlaot',
which is of non-class type `int'
Czytam „Struktury danych dla programistów gier” Rona Pentona, autor podaje float
, ale kiedy próbuję, nie wydaje się, aby się kompilował.
c++
templates
generics
floating-point
yokks
źródło
źródło
float
jako parametru szablonu innego niż typ ? W którym to rozdziale?Odpowiedzi:
Obecny standard C ++ nie zezwala
float
(tj. Liczby rzeczywistej) lub literałów ciągu znaków na używanie jako parametrów innych niż typowe dla szablonu . Możesz oczywiście używać typówfloat
ichar *
jako zwykłych argumentów.Być może autor używa kompilatora, który nie jest zgodny z obecnym standardem?
źródło
template<char ...cs>
, to literał ciągu można przekształcić w taki pakiet w czasie kompilacji. Oto demo ideone . (Demo to C ++ 14, ale łatwo jest go przenieść z powrotem do C ++ 11 -std::integer_sequence
to jedyna trudność)char &*
jako parametru szablonu, jeśli zdefiniujesz literał w innym miejscu. Działa całkiem nieźle jako obejście.PROSTA ODPOWIEDŹ
Standard nie dopuszcza zmiennoprzecinkowych jako argumentów szablonowych innych niż typowe , o których można przeczytać w poniższej sekcji standardu C ++ 11;
Ale… ale… DLACZEGO !?
Wynika to prawdopodobnie z faktu, że obliczeń zmiennoprzecinkowych nie można przedstawić w dokładny sposób. Gdyby było dozwolone, mogłoby / spowodowałoby błędne / dziwne zachowanie podczas robienia czegoś takiego;
Chcieliśmy wywołać tę samą funkcję dwa razy, ale może tak nie być, ponieważ nie ma gwarancji, że reprezentacja zmiennoprzecinkowa dwóch obliczeń będzie dokładnie taka sama.
Jak przedstawiłbym wartości zmiennoprzecinkowe jako argumenty szablonu?
Ze
C++11
można napisać całkiem zaawansowanych stałym wyrażeń ( constexpr ), które mogłyby obliczyć licznik / mianownik pływającej czasie wartość kompilacji, a następnie przekazać te dwa odsunięte całkowitych.Pamiętaj, aby zdefiniować jakiś rodzaj progu, aby wartości zmiennoprzecinkowe blisko siebie dawały ten sam licznik / mianownik , w przeciwnym razie jest to trochę bezcelowe, ponieważ wtedy da ten sam wynik wspomniany wcześniej jako powód, aby nie zezwalać na wartości zmiennoprzecinkowe jako inne niż typ argumenty szablonu .
źródło
<ratio>
opisane w §20.10 jako „arytmetyka racjonalna czasu kompilacji”. Co dobrze pasuje do twojego przykładu.<ratio>
?12345 * 12345
to jest? (To nie pozwalająint
parametrów szablonu, mimo że nie określa szerokość podpisanego int, czy też, że wyrażenie jest UB.)Wystarczy podać jeden z powodów, dla których jest to ograniczenie (przynajmniej w obecnym standardzie).
Podczas dopasowywania specjalizacji szablonu kompilator dopasowuje argumenty szablonu, w tym argumenty inne niż typowe.
Ze swej natury wartości zmiennoprzecinkowe nie są dokładne, a ich implementacja nie jest określona przez standard C ++. W rezultacie trudno jest zdecydować, kiedy dwa argumenty zmiennoprzecinkowe nietypowe naprawdę pasują do siebie:
Wyrażenia te niekoniecznie generują ten sam „wzorzec bitowy”, więc nie byłoby możliwe zagwarantowanie, że używają tej samej specjalizacji - bez specjalnego sformułowania, które to obejmuje.
źródło
==
operatora :-) Akceptujemy już tę niedokładność w czasie wykonywania, dlaczego nie również w czasie kompilacji?Rzeczywiście, nie można używać literałów typu float jako parametrów szablonu. Patrz sekcja 14.1 („Parametr szablonu inny niż typ powinien mieć jeden z następujących (opcjonalnie kwalifikowanych jako CV) typów…”) normy.
Możesz użyć odwołania do float jako parametru szablonu:
źródło
Umieść parametr (y) w ich własnej klasie jako constexprs. W rzeczywistości jest to podobne do cechy, ponieważ parametryzuje klasę za pomocą zestawu liczb zmiennoprzecinkowych.
a następnie utwórz szablon, przyjmując typ klasy jako parametr
a potem użyj go tak ...
Dzięki temu kompilator może zagwarantować, że dla każdego wystąpienia szablonu z tym samym pakietem parametrów zostanie utworzone tylko jedno wystąpienie kodu. To omija wszystkie problemy i możesz używać pływaków i podwajać jako constexpr wewnątrz klasy szablonowej.
źródło
Jeśli możesz mieć stałą wartość domyślną dla typu, możesz utworzyć typ, aby zdefiniować go jako stałą i wyspecjalizować go w razie potrzeby.
Jeśli masz C ++ 11, możesz użyć constexpr podczas definiowania wartości domyślnej. W C ++ 14 MyTypeDefault może być zmienną szablonu, która jest nieco czystsza pod względem składniowym.
źródło
Inne odpowiedzi dają dobre powody, dla których prawdopodobnie nie chcesz parametrów szablonu zmiennoprzecinkowego, ale prawdziwym IMO hamującym transakcje jest to, że równość przy użyciu '==' i równości bitowej to nie to samo:
-0.0 == 0.0
, ale0.0
i-0.0
nie są równe bitowoNAN != NAN
Żaden rodzaj równości nie jest dobrym rozwiązaniem dla równości typów: oczywiście, punkt 2. sprawia, że użycie
==
równości typów jest nieprawidłowe. Zamiast tego można by użyć równości bitowej, ale wtedyx != y
nie oznacza toMyClass<x>
iMyClass<y>
są to różne typy (przez 2.), co byłoby raczej dziwne.źródło
Zawsze możesz to udawać ...
Ref: http://code-slim-jim.blogspot.jp/2013/06/c11-no-floats-in-templates-wtf.html
źródło
float
! = Liczba wymierna. Są to bardzo różne pomysły. Jedna jest obliczana za pomocą mantysy i wykładnika, druga jest, cóż, racjonalna - nie każda wartość reprezentowana przez racjonalną jest reprezentowana przez afloat
.float
jest zdecydowanie liczbą wymierną, ale są liczby,float
których nie można przedstawić jako proporcje dwóchint
s. Mantysa jest liczbą całkowitą, a wykładnik 2 ^ jest liczbą całkowitąJeśli nie potrzebujesz podwójnego, aby był stałą czasu kompilacji, możesz przekazać go jako wskaźnik:
źródło
Począwszy od C ++ 20 jest to możliwe .
To również daje odpowiedź na pierwotne pytanie:
Ponieważ nikt jeszcze tego nie wdrożył w standardzie. Nie ma żadnego podstawowego powodu.
W C ++ 20 parametrach szablonów innych niż typowe mogą teraz być zmiennoprzecinkowe, a nawet obiekty klas.
Istnieją pewne wymagania dotyczące obiektów klas (muszą być typem literału ) i spełniają inne wymagania, aby wykluczyć patologiczne przypadki, takie jak operator zdefiniowany przez użytkownika == ( Szczegóły ).
Możemy nawet użyć
auto
Zauważ, że GCC 9 (i 10) implementuje parametry szablonu inne niż klasowe, ale jeszcze nie dla liczb zmiennoprzecinkowych .
źródło
Jeśli chcesz reprezentować tylko stałą precyzję, możesz użyć takiej techniki, aby przekonwertować parametr float na wartość int.
Na przykład tablicę ze współczynnikiem wzrostu 1,75 można utworzyć w następujący sposób, zakładając 2 cyfry dokładności (podzielenie przez 100).
Jeśli nie podoba ci się reprezentacja 1,75 jako 175 na liście argumentów szablonu, zawsze możesz owinąć ją jakimś makrem.
źródło
...::Factor = _Factor_/100.0;
inaczej będzie to dzielenie liczb całkowitych.