2010-09-27 3 views
11

Section 4.3 de C++ Templates états « Ne pas être en mesure d'utiliser littéraux à virgule flottante (et simples expressions à virgule flottante constant) comme arguments de modèle a raisons historiques ».spécialisation de modèle avec flotteur comme type non

De même,

14.1 $/7 états - « Un modèle paramètre non-type ne doit pas être déclarés avoir à virgule flottante, classe ou type void [Exemple:

.
template<double d> class X; // error 
template<double* pd> class Y; // OK 
template<double& rd> class Z; // OK" 
  1. Quelle est la raison historique qui est bein g parlé dans le livre dans la citation ci-dessus? En regardant pourquoi Y et Z sont valides mais pas X, est-ce que tout le défi lié au fait que les paramètres de type non-type de type flottant aient quelque chose à faire avec des pointeurs/références? Pourquoi les paramètres de type non-type ne peuvent-ils pas être de type classe?

+0

@aaa carp: Oui, je pourrais comprendre cela. Je suis curieux de savoir quelle est la raison historique pour refuser les types à virgule flottante. Aussi j'essaie de comprendre pourquoi X est mal formé par pas Y ou Z. – Chubsdad

+0

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/2f4c0b5a5ae627bc/bbe916d9e75426de?hl=fr&ie=UTF -8 & oe = utf-8 & q = virgule flottante + littéraux +% 28as + modèle + arguments + historique + raisons & pli = 1 – Anycorn

+0

@aaa carpe: non, ce n'est pas le cas. L'adresse transmise ne serait connue que de l'éditeur de liens, mais le compilateur en a déjà besoin pour instancier. – MSalters

Répondre

5

nombres à virgule flottante ne sont pas représentés universelle (et certaines valeurs ne peuvent même pas être représentés sans perte de précision depuis sa base sur l'approximation) et peuvent donc être différentes d'une plateforme à l'origine du même code C++ générer différents modèles sur différentes plates-formes.

(On peut dire que C++ prend en charge la compilation croisée sans nécessiter le compilateur d'imiter totalement l'arithmétique en virgule flottante de la machine cible. Permettant float ou double comme paramètre de modèle invaliderait ce.)

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

Par exemple, squared_float < 1.0> pourrait avoir la même fonction que squared_float.00000001> sur certaines implémentations, alors que sur d'autres, elles auraient deux fonctions différentes.


Un reference to a float signifie que le compilateur peut l'optimiser car il connaît sa valeur et qu'il ne devrait jamais changer.

Pour pointer, c'est juste un autre type de données dépendant de l'architecture (32 bits/64 bits) qui n'a rien à voir avec float.

+0

Sur une plate-forme donnée cependant cela ne devrait pas être un problème. Cela peut cependant affecter la portabilité, ce qui est vrai pour tant d'autres fonctionnalités dans le langage, par ex. sizeof (int) – Chubsdad

10

Il peut être difficile de choisir le bon modèle d'instantitiation, en raison d'éventuelles erreurs d'arrondi.

Considérez ce qui suit:

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

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

f(1/3); -> Quelle version serait appelée?

Considérez le code suivant:

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

"Qu'est-ce que devrait générer le compilateur Le compilateur doit connaître les détails de la cible architecture à virgule flottante pour être en mesure d'exécuter instancier le modèle Ceci est. assez facile si le compilateur est en cours d'exécution sur l'architecture cible , il peut juste faire le calcul et trouver la réponse, mais si vous faites une compilation croisée, le compilateur devrait être en mesure de synthétiser le comportement à virgule flottante de chaque l'architecture cible prévue etHeureusement, le Comité des normes a décidé que cela serait déraisonnable. "

Shamelessly copié à partir here.

Pourquoi paramètres non type de modèle ne peut pas être de type classe

Selon ma compréhension un paramater non type ne peut pas être de type classe car il peut y avoir plus d'une mise en œuvre d'une classe. Par exemple

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

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


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

Les classes locales ne peuvent pas être utilisées comme paramètres de modèle car they don't have external linkage.

+0

0.3333 est de type 'double' n'est-ce pas ce qui est le même que le type de 1/3? Donc le compilateur peut choisir la spécialisation pour 'double' avec par défaut comme <0.3333> – Chubsdad

+0

cela semble raisonnable, IEEE repr a été introduit en 1985, en même temps C++ est devenu "officiel", donc peut-être il n'y avait pas de mathématiques standard pour le virgule flottante – Anycorn

+1

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

1

Le codage exact des valeurs à virgule flottante est plus sujet à des bizarreries de processeurs individuels. Par exemple, lors de l'évaluation d'une expression supposée constante, un processeur devrait-il utiliser des registres de processeurs 80 bits de plus haute précision et revenir seulement à 64 bits à la fin? Si un compilateur dit oui et un autre non, le modèle aura deux instanciations distinctes. Mais, certains autres compilateurs peuvent avoir seulement des registres 64 bits, et peut-être que différents processeurs peuvent varier d'une valeur epsilon. L'ordre dans lequel un compilateur choisit d'évaluer une expression, ou si une bibliothèque a été compilée à l'aide d'une bibliothèque d'émulation à virgule flottante, etc., peut provoquer de telles erreurs. De plus, les nombres à virgule flottante ont des cas de bords étranges: positifs et négatifs 0, etc., pour lesquels un comportement devrait être défini.

Ces problèmes peuvent potentiellement mordre dans des environnements où les objets sont compilés sur des machines différentes (avec différents processeurs, les versions du compilateur et des drapeaux, etc.), mais la nécessité de relier de manière fiable. Les entreprises le font généralement, et les bibliothèques distribuées en binaire sont également confrontées à de tels problèmes. Les compilateurs C++ essaient généralement d'adopter une interface binaire d'application (ABI) aussi cohérente que possible entre les versions et les environnements, mais ceux-ci ne normalisent pas actuellement la façon dont les paramètres en virgule flottante ont été calculés, et ce n'est pas évident. attendre de tous les compilateurs qu'ils utilisent la même émulation à virgule flottante pour dériver les valeurs. Cela nécessiterait un effort de coordination et les solutions d'émulation existantes pourraient avoir des problèmes de licence. Fait intéressant, Walter Bright (de Digital Mars) pensait que tout était merdique et permettait des constantes à virgule flottante dans D ... il suppose qu'il a eu une expérience du monde réel des conséquences qui seraient utiles à la communauté C++, mais je n'ai pas entendu récemment.

+0

il y a quelques trucs MPL dans le coffre-fort qui permettent les constantes FP. – Anycorn

+0

hmmm ... J'évite MPL - Boost ennuyé a refusé de loger Loki alors que les docs disponibles en ligne pour MPL sont les pires de toute la collection Boost et IMHO un flagrant "Je vais gagner de l'argent ici parce que je suis en contrôle de booster "annonce pour les livres, tandis que d'autres auteurs boivent sont censés vivre réellement par le général" partager librement avec la communauté "esprit booster aime à épouser publiquement –

+0

[Nous pourrions lui demander] (http://stackoverflow.com/users/ 33949/walter-bright) –

1

Une solution à ce problème est d'utiliser des nombres rationnels. Envoyer deux entiers paramètres non de type, puis initialiser votre flotteur dans le constructeur comme suit

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

le tour est joué, le passage d'un float.

+0

Si vous utilisez C++ 11, 'std :: ratio' fonctionne bien pour cela. – Ponkadoodle

+0

Mais comment transformer le ratio std :: en un flottant? – Ant6n

0

Une solution possible à ce problème consiste à utiliser un type qui a une valeur constante qui est un flottant, puis utiliser ce type comme paramètre de modèle. Par exemple, si vous voulez avoir un polynôme entier, par exemple, et que vous voulez l'évaluer à une valeur en virgule flottante compilation:

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

On pourrait aussi utiliser des classes d'aide qui permettent de créer des classes de flotteurs, par exemple pour pour cent:

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>> 
... 

Je suppose que cela est similaire à l'utilisation du std::ratio mentionné précédemment.

Questions connexes