134 votes

Pourquoi ne puis-je pas utiliser float valeur d'un paramètre du modèle?

Lorsque j'essaie d'utiliser float comme un paramètre du modèle, le compilateur pleure pour ce code, tout en int fonctionne très bien.

Est-ce parce que je ne peux pas utiliser float comme un paramètre de modèle?

#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;       
}

Erreur:

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'

Je suis à la lecture de "Structures de Données pour les Programmeurs de jeux" par Ron Penton, l'auteur passe un float, mais quand je l'ai essayer il ne semble pas à compiler.

147voto

Filip Roséen - refp Points 24995

LA RÉPONSE SIMPLE

La norme ne permet pas de floating points comme non-type de modèle-arguments, qui peut être lu dans la section suivante du C++11 standard;

14.3.2/1 Modèle non-arguments de type [temp.arg.nontype]

Un modèle d'argument pour un non-type, non-template template-parameter doit être:

  • pour un non-type de modèle à paramètre d'intégrales ou de type énumération, un converti expression constante (5.19) du type de la template-parameter;

  • le nom d'un non-type de modèle à paramètre; ou

  • une expression constante (5.19) qui désigne l'adresse d'un objet statique de la durée de stockage et externe ou interne de liaison ou d'une fonction externe ou interne de liaison, y compris la fonction les modèles et le modèle de fonction-id, mais à l'exclusion des non-statique de la classe membres, exprimée (en ignorant les parenthèses) & id-expression, à l'exception de que l' & peut être omis si le nom fait référence à une fonction ou un tableau et doit être omis si le modèle correspondant paramètre est un de référence; ou

  • une expression constante qui donne une valeur de pointeur null (4.10); ou

  • une constante expression qui renvoie une valeur null membre de la valeur du pointeur (4.11); ou

  • un pointeur sur membre, tel que décrit à l'article 5.3.1.


Mais.. mais.. POURQUOI!?

C'est probablement dû au fait que floating points ne peuvent pas être représentées de manière exacte. Si c'était autorisé, il pourrait/aurait pour résultat erroné/comportement bizarre quand vous faites quelque chose comme cela;

func<1/3.f> (); 
func<2/6.f> ();

Nous avons pour but d'appeler la même fonction deux fois, mais cela pourrait ne pas être le cas étant donné la représentation à virgule flottante de deux calculs n'est pas garanti d'être exactement le même.


Comment pourrais-je représenter les valeurs à virgule flottante comme arguments de modèle?

Avec C++11 vous pouvez écrire quelques assez avancée constante des expressions (constexpr) qui permettrait de calculer le numérateur/dénominateur d'une valeur flottante moment de la compilation et de transmettre ensuite ces deux distincts arguments entiers.

N'oubliez pas de définir une sorte de seuil, de sorte que les valeurs à virgule flottante proches les uns des autres, vous obtiendrez le même numérateur/denomitor, sinon c'est un peu inutile puisqu'il va ensuite donner le même résultat précédemment mentionné comme raison de ne pas permettre à des valeurs à virgule flottante en tant que non-gabarit de type d'arguments.

37voto

Richard Corden Points 12292

Juste pour donner une des raisons pour lesquelles c'est une limitation (dans la norme actuelle au moins).

Lors de l'appariement des spécialisations de modèle, le compilateur correspond aux arguments de modèle, y compris les non-type d'arguments.

De par leur nature, les valeurs à virgule flottante ne sont pas exactes et leur mise en œuvre n'est pas spécifié par la norme C++. En conséquence, il est difficile de décider quand deux virgule flottante non des arguments de type vraiment de match:

template <float f> void foo () ;

void bar () {
    foo< (1.0/3.0) > ();
    foo< (7.0/21.0) > ();
}

Ces expressions ne produisent pas nécessairement le même "pattern" et donc il ne serait pas possible de garantir qu'ils ont utilisé la même spécialisation - sans texte à ce.

21voto

moonshadow Points 28302

En effet, vous ne pouvez pas utiliser float littéraux paramètres du modèle. Voir l'article 14.1 ("non-type de modèle-paramètre doit avoir une des options suivantes (en option cv qualifiés) types de...") de la norme.

Vous pouvez utiliser une référence à l'flotter comme un paramètre du modèle:

template <class T, T const &defaultValue>
class GenericClass

.
.

float const c_four_point_six = 4.6; // at global scope

.
.

GenericClass < float, c_four_point_six> gcFlaot;

0voto

jurujen Points 1

Si vous ne voulez représenter une précision fixe, alors vous pouvez utiliser une technique de ce genre pour convertir un float paramètre dans un int.

Par exemple un tableau avec un facteur de croissance de 1,75 pourrait être créé comme suit, en supposant que 2 chiffres de précision (diviser par 100).

template <typename _Kind_, int _Factor_=175>
class Array
{
public:
    static const float Factor;
    _Kind_ * Data;
    int Size;

    // ...

    void Resize()
    {
         _Kind_ * data = new _Kind_[(Size*Factor)+1];

         // ...
    }
}

template<typename _Kind_, int _Factor_>
const float Array<_kind_,_Factor_>::Factor = _Factor_/100;

Si vous n'aimez pas la représentation de 1,75 175 dans le modèle de la liste d'arguments ensuite, vous pouvez toujours l'envelopper dans certains macro.

#define FloatToIntPrecision(f,p) (f*(10^p))

template <typename _Kind_, int _Factor_=FloatToIntPrecision(1.75,2)>
// ...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X