C++11

C++11

C++11, anciennement connu sous le nom de C++0x[1], est la nouvelle norme pour le langage C++ en informatique. Elle a été approuvée unanimement le 12 août 2011[2]. Elle vise à remplacer la norme existante, ISO/CEI 14882, publiée en 1998 et mise à jour en 2003. Ces dernières sont plus connues sous les noms informels de C++98 et C++03. La nouvelle norme introduira plusieurs nouveautés au langage initial, ainsi que de nouvelles fonctionnalités à la bibliothèque standard du C++ comme la plupart des bibliothèques du Technical Report 1, à l'exception de la bibliothèque de fonctions mathématiques spéciales. Cette norme n'étant pas à l'heure actuelle finalisée, cet article pourrait ne pas refléter l'état d'avancement courant de C++11, qui est publié sur le site de comité de la norme ISO C++. Le rapport le plus récent, N2597, a été publié en février 2011.

Le comité de normalisation ISO/CEI JTC1/SC22/WG21 du C++ a eu pour but de présenter la nouvelle norme en 2009, ce qui signifie que le document devait être prêt pour la ratification par les membres de l'ISO en 2008. Pour pouvoir finir en temps et en heure, le comité a décidé de concentrer ses efforts sur les solutions apportées jusqu'à 2006 et d'ignorer toutes les nouvelles propositions. La norme a finalement été votée et approuvée à l'unanimité le 12 août 2011.

Un langage de programmation comme le C++ suit une évolution qui permet aux programmeurs de coder plus rapidement, de façon plus élégante et permettant de faire du code maintenable. Ce processus soulève inévitablement des questions de compatibilité avec le code existant, ce qui s'est produit de temps en temps pendant le processus de développement du C++. Cependant, d'après l'annonce faite par Bjarne Stroustrup (l'inventeur du langage C++ et membre du comité), la nouvelle norme sera presque totalement compatible avec la norme actuelle.

Sommaire

Changements prévus pour la mise à jour de la norme

Comme dit précédemment, les changements du langage C++ concerneront aussi bien le langage initial que la bibliothèque standard.

Durant le développement de chaque fonctionnalité de la nouvelle norme, le comité a appliqué les directives suivantes :

  • Garder la stabilité et la compatibilité avec le C++98 et, si possible, avec le C.
  • Préférer l'introduction de nouvelles fonctionnalités par la bibliothèque standard, plutôt que par le langage lui-même.
  • Préférer les changements qui peuvent faire évoluer les techniques de programmation.
  • Améliorer le C++ pour faciliter la mise en place de systèmes et de bibliothèques, plutôt qu'introduire de nouvelles fonctionnalités seulement utiles pour des applications spécifiques.
  • Augmenter la protection des types en fournissant des alternatives plus sécurisées que les actuelles, plutôt non sécurisées.
  • Augmenter les performances et les capacités à travailler directement avec le matériel.
  • Proposer des solutions propres aux problèmes actuels.
  • Implémenter le principe du “zero-overhead” (seulement les supports nécessaires doivent être inclus).
  • Rendre le C++ facile à apprendre et à enseigner sans enlever les fonctionnalités requises par les programmeurs experts.

Extensions du langage

Multitâche

Mémoire locale pour un thread

La mémoire locale de thread ou Thread Local Storage n'est pas un concept inventé par la nouvelle norme : de nombreux compilateurs proposent déjà cette fonctionnalité, ainsi que la bibliothèque threads de Boost. C++11 introduit le mot-clef thread_local pour déclarer qu'une variable doit être stockée dans une zone mémoire appartenant au thread. Chaque thread embarque ainsi sa propre copie d'une variable déclarée de la sorte, et les modifications d'une de ces copies n'affectent pas les copies appartenant aux autres threads. Lorsqu'une variable statique (ou une variable de classe) est ainsi définie, sa durée de vie est alors réduite à celle du thread (le destructeur des objets, notamment, est appelé lorsque le thread s'achève).

Le modificateur volatile

Les classes

Délégation du constructeur

En C++, un constructeur appartenant à une classe ne peut pas appeler un autre constructeur de cette même classe, ce qui peut entraîner de la duplication de code lors de l'initialisation de ses attributs. En permettant au constructeur de déléguer la création d'une instance à un autre constructeur, C++0x apporte donc une solution.

class une_classe {
    int nombre;
 
public:
    une_classe(int nouveau_nombre) : nombre(nouveau_nombre) {}
    une_classe() : une_classe(42) {}
};

Dans l'exemple ci-dessus, on peut voir que le second constructeur appelle le premier constructeur, ce qui aurait conduit à une erreur de compilation en C++.

Héritage du constructeur

Initialiseurs d'attributs

Sizeof sur les attributs de classes sans objet explicite

Suppression et mise à défaut des fonctions standards des objets

Opérateur de conversion explicite

Liste d'initialiseurs

Pour initialiser un conteneur à l'aide de valeurs connues, il fallait utiliser une séquence de tableau. C++11 introduit le patron de classe std::initializer_list qui permet d'initialiser les conteneurs comme les tableaux, à l'aide d'une suite de valeurs entre accolades.

Modification de la définition des POD (Plain Old Data)

Les Templates

Article détaillé : Template (programmation).

Alias de templates grâce au mot-clé using (template typedef)

Les templates variadiques

Pour remplacer les fonctions variadiques du C (déconseillées en C++), C++0x introduit les templates variadiques. Ces templates étendent le concept précédent en lui ajoutant la possibilité de prendre un nombre quelconque d'arguments. Elles sont supportées par le compilateur GCC depuis la version 4.3 car elles font partie de l'expérimentation du support de C++0x[3].

L'utilité de templates possédant un nombre quelconque d'argument se perçoit aisément avec la classe tuple, qui généralise le concept de pair, ou bien avec cet exemple d'implémentation de la fonction printf :

void printf(const char *s)
{
  while (*s)
    std::cout << *s++;
}
 
template<typename T, typename... Args>
void printf(const char* s, const T& value, const Args&... args) {
  while (*s) {
    if (*s == '%' && *++s != '%') {
      std::cout << value;
      printf(++s, args...);
      return;
    }
    std::cout << *s++;
  }
  throw std::runtime_error("extra arguments provided to printf");
}

C++0x définit un certain nombre de concepts que nous pouvons approcher grâce au code source suivant :

template<class ... T> struct Tuple { };
 
template<class ... T> 
void f(T ... args);
 
template<class ... T> void g(T ... a); 
template<class ... T> void h(T ... b) 
{ 
   g(b ...); 
}
  • À la première déclaration, l'argument template class ... T est appelé un pack de paramètres template car il regroupe un nombre fini d'arguments (déterminé à la compilation).
  • À la seconde déclaration, T ... args s'appelle un pack de paramètres de fonction. C'est un paramètre de fonction qui englobe un paramètre pour chaque argument contenu par le pack de paramètres template class ... T.
  • Enfin, la troisième déclaration nous apprend comment utiliser un pack étendu de paramètres. Le mot extension est utilisé car lors de l'appel à g, le pack de paramètres sera étendu avant d'être passé à g.

Les concepts

Les concepts ont été retirés de la prochaine norme.

Les chevrons (<>)

Les compilateurs C++ actuels traitent toujours une séquence de deux signes supérieur à comme un opérateur de décalage binaire vers la droite. En conséquence, lors de l'imbrication de l'utilisation de patrons, les programmeurs sont obligés d'insérer un espace entre les deux chevrons fermants.

Par exemple, en C++03, ce code provoque une erreur de compilation :

#include <vector>
std::vector<std::vector<int>> matrix;
// Attention ! Écrire plutôt : “std::vector<std::vector<int> >”

C++11 tentera de détecter automatiquement si les symboles doivent jouer le rôle de chevrons fermants ou d'opérateur de décalage binaire.

Template externe

Les templates ne sont actuellement pas pris en compte par l'éditeur de liens : il est nécessaire d'incorporer leur définition dans tous les fichiers sources les utilisant en programmation modulaire. Leur compilation était donc longue et gourmande puisque la classe était recompilée dans chaque fichier source, pour chaque type utilisé.

C++11 permettra l'utilisation du mot-clé extern pour rendre les templates globaux. Les fichiers désirant utiliser le template n'ont qu'à le déclarer.

Autres nouvelles fonctionnalités du C++11

Expressions constantes généralisées

Assertions statiques

La bibliothèque Boost propose déjà cette facilité à travers la macro BOOST_STATIC_ASSERT. Cependant, son implémentation est étrange, basée sur la métaprogrammation et des comparaisons de taille de structures intermédiaires créées pour l'assertion sans trop de rapport avec le concept. Par conséquent, intégrer la fonction dans le langage apporte une solution propre au problème.

En pratique, une assertion statique permet de vérifier à la compilation qu'une valeur est vraie. Par exemple, il est possible d'implémenter les concepts en utilisant boost::traits et BOOST_STATIC_ASSERT. Si une classe template nécessite que son type template soit un POD, elle peut faire une assertion statique sur boost::is_pod<T>::type::value, ce qui est une constante intégrale de type unspecified-bool-type et remplit dont le critère pour paraître dans une assertion statique.

En outre, en C++11, l'expression :

static_assert(sizeof(long) > sizeof(int));

permettrait à une bibliothèque d'être certaine qu'elle est compilée sur un système vérifiant cette condition (x86-64 par exemple).

static_assert permet aussi de préciser un message d'erreur. Dans ce cas-là, l'assertion précédente ressemblerait à :

static_assert(sizeof(long) > sizeof(int), "La bibliothèque doit être compilée sous un système 64-BIT");

Expressions et fonctions lambda

Inférence de types

Le mot clé auto se voit assigner une nouvelle sémantique par le nouveau standard. Nous connaissions son unique sémantique d'indicateur de classe de stockage pour une variable. En effet, déclarer une variable automatique revenait à indiquer au compilateur qu'elle était valide seulement dans l'espace où elle était déclarée ; ce comportement étant aussi celui par défaut, le mot clé était inutile. Dans le nouveau standard, il change de sémantique et prend la place du type dans la déclaration. Le type sera alors automatiquement décidé par correspondance avec le type retourné par l'objet utilisé pour l'initialisation de la variable. Les variables étant déclarées avec auto devront donc impérativement être initialisées. Exemple :

auto f = boost::bind(MyFunc, _1);
f(5);

Le type de f est un type interne de la bibliothèque surchargé environ quatre-vingts fois avec un script Perl. Trouver le type exact pour stocker le résultat d'un bind dans un objet n'était pas pratique du tout avant le nouveau rôle du mot clé auto, d'où son apparition.

Le nouveau standard ajoute le mot clé decltype qui permet de typer une variable à partir du type d'une autre variable. Exemple:

int i;
decltype(i) j = 5;

Le type de j sera du même type que i, soit int. Cette déclaration automatique du type d'une variable peut être très utile dans les templates.

Sémantique des RValues Reference/Move

L'introduction de la sémantique move prend son sens en constatant qu'en C++, il n'y a aucune une manière générique de déplacer un objet sans le copier. Par exemple, la commande swap est souvent introduite par le patron de fonction ci-dessous :

template <class T>
void swap ( T& a, T& b )
{
  T c(a); 
  a=b; 
  b=c;
}

Cette fonction a pour inconvénient d'appeler d'abord le constructeur de recopie, puis deux opérateurs d'assignation. Ce sont donc 3 copies au total, qui peuvent être des opérations extrêmement coûteuses, voire impossibles si les objets impliqués sont de taille importante. C++11 introduit la sémantique move pour résoudre ce problème : la fonction move() retourne une référence à une rvalue (parfois aussi appelée temporaire) et prend pour paramètre une référence à une lvalue ou à une rvalue. Le concept de référence à une rvalue est introduit par la norme.

template <class T>
typename remove_reference<T>::type&&
move(T&& a)
{
    return a;
}

La fonction move() donne à ce qu'il retourne la valeur de son paramètre, mais n'est pas contrainte de préserver les données de sa source. Autrement dit, move() est une fonction de lecture potentiellement destructrice. Le point important de move est qu'il n'y a aucune copie de faite. En utilisant move, on peut ainsi réécrire de façon concise swap(), sans qu'il n'y ait de copie.

template <class T> 
swap(T& a, T& b)
{
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

Énumérations fortement typées

L'énumération du langage C était similaire à une liste de définitions de symboles (macros) correspondant à des nombres entiers, et C++ n'avait répondu qu'en interdisant la conversion d'un type énumération dans un autre.

C++11 proposera des énumérations « fortement typées ». Ces énumérations seront obtenues en remplaçant enum par enum class ou enum struct[4]. La conversion d'éléments de ces énumérations vers les entiers sera prohibée et l'accès aux éléments se fera à l'aide de l'opérateur de résolution de portée. Voici un exemple d'utilisation :

enum class Chiffres { Zero, Un, Deux, Trois, Quatre, Cinq, Six, Sept, Huit, Neuf };
Chiffres chif;
chif = Chiffres::Sept;
int nb;
nb = (int) Chiffres::Trois;

L'opérateur de résolution de portée sera optionnel avec des énumération faiblement typées :

enum Enum2 { E_1, E_2 };
Enum2 e1 = E_1; // Comme en C++03
Enum2 e2 = Enum2::E_2; // Comme avec une enum class;

De plus, C++11 vous permettra de choisir le type d'entier sous-jacent des énumérations (tous sauf wchar_t):

enum class Enumeration : unsigned short { Valeur1, Valeur2 };

Par défaut, ce type sera int. Ce comportement sera aussi possible avec les énumérations normalement typées, et il sera bien sûr toujours possible de définir la valeur d'une partie de l'énumération :

enum EnumerationNormale : UINT8 { ValeurDepart = 0, ValeurMoyenne = 127, ValeurMaximum = 255 };

Boucles basées sur des intervalles

Le code nécessaire en C++ pour le parcours d'un intervalle et l'action sur ses éléments est répétitif et long. De nombreux langages, comme Java, ont fourni à leurs utilisateurs un opérateur foreach qui permet de parcourir une liste avec aisance[5]. Pour répondre aux attentes, la norme C++11 fournira une nouvelle syntaxe de l'instruction for qui s'implémentera de cette façon :

int mon_tableau[5] = {1, 2, 3, 4, 5};
for (int &x: mon_tableau) {
    x *= 2;
}

Ce code permet de doubler tous les éléments du tableau mon_tableau. L'entier x défini pour le corps de la boucle for référence successivement chacun des éléments du tableau.

Ce type de parcours fonctionnera pour les listes classiques, les listes d'initialiseurs, ainsi que les conteneurs de la STL définissant les fonctions membres begin et end.

Nouveaux littéraux « chaînes de caractères »

Littéraux définis par l'utilisateur

Destruction des objets transparente

Pointeur NULL

Le nouveau mot-clé nullptr a été proposé comme constante du langage avec le caractère particulier d'être assignable à tous les types de pointeurs. En effet, contrairement au C où la macro préprocesseur est généralement définie avec #define NULL ((void*)0), en C++ il est interdit d'assigner un void* à un pointeur d'un type différent. L'usage était donc de définir NULL avec l'entier 0. Ce comportement restera compatible, mais il sera aussi possible d'écrire :

T* ptr = nullptr;

Extension de la bibliothèque standard

Améliorations des threads

Le type tuple

Un tuple est une collection de dimension fixe d'objets de types différents. Tous types d'objets peut être élément d'un tuple. Cette nouvelle fonctionnalité est implémentée dans un nouvel en-tête et bénéficie des extensions de C++11 comme :

Le patron de classe tuple est déclaré par la ligne :

template <class... Types> class tuple;

Un exemple de définition et d'utilisation du type tuple :

typedef tuple< int, double, long &, const char * > test_tuple ;
long lengthy = 12 ;
test_tuple proof( 18, 6.5, lengthy, "Ciao!" ) ;
lengthy = get<0>(proof) ;  // Assigne à ‘lengthy’ la valeur 18
get<3>(proof) = " Beautiful!" ;  // Modifie la 4ème valeur du tuple

Il est possible de créer le tuple proof sans définir son contenu si les éléments du tuple possèdent un constructeur par défaut. De plus, il est possible d'assigner un tuple à un autre tuple : si les deux tuples sont de même type, il est nécessaire que chaque élément du tuple ait un constructeur par copie, sinon il faut que le type de chaque élément de l'opérande de droite soit compatible avec le type correspondant dans l'opérande de gauche ou que l'élément correspondant de l'opérande gauche ait un constructeur approprié.

typedef tuple< int , double, string       > tuple_1 t1 ;
typedef tuple< char, short , const char * > tuple_2 t2( 'X', 2, "Hola!" ) ;
t1 = t2 ;  // OK : les deux premiers éléments peuvent être convertis,
           // le troisième peut être construit à partir du ‘const char *’.

Les opérateurs relationnels sont disponibles (pour les tuples ayant le même nombre d'éléments). Deux expressions sont introduites pour vérifier les caractéristiques d'un tuple (à la compilation) :

  • tuple_size<T>::value retourne le nombre d'éléments du tuple T,
  • tuple_element<I, T>::type retourne le type de l'objet placé en position I du tuple T.

Table de hachage

Intégrer les tables de hachage (conteneurs associatifs non ordonnés) dans la bibliothèque standard du C++ est l'une des demandes les plus récurrentes. Cela n'avait pas été réalisé pour la norme actuelle (celle écrite en 1995 et approuvée en 1998) à cause des contraintes de temps. Bien que cette solution soit moins efficace que les arbres équilibrés dans le pire des cas (en cas de collisions importantes), elle est cependant la meilleure dans la plupart des applications réelles.

Les collisions seront uniquement gérées par chaînage linéaire car le comité ne considère pas opportun de standardiser des solutions d'adressage ouvert qui introduisent un nombre important de problèmes intrinsèques (en particulier quand la suppression d'éléments est permise). Pour éviter les conflits de noms avec les bibliothèques non standards qui ont leur propre implémentation des tables de hachage, on utilisera le préfixe unordered, au lieu de hash.

Cette nouvelle fonctionnalité intégrera quatre types de tables de hachage, différentes selon qu'elles acceptent ou non des éléments de même clé (clé unique ou clé équivalente) et qu'elles associent chaque clé à la valeur associée.

Type de table de hachage Type associé arbitraire Clés équivalentes
unordered_set
unordered_multiset
unordered_map
unordered_multimap

Ces nouvelles classes remplissent toutes les demandes des classes de conteneurs et contiennent toutes les méthodes nécessaires pour accéder aux éléments : insert, erase, begin, end.

Ces classes n'ont pas nécessité les nouvelles extensions du langage C++ mais seulement une légère extension du header <functional> et l'introduction des headers <unordered_set> et <unordered_map>. Aucun autre changement aux classes de la norme actuelle n'est nécessaire et elles ne dépendent d'aucune autre extension de la bibliothèque standard.

Expressions régulières

“Smart pointer” généraux

Amélioration des nombres aléatoires extensibles

La bibliothèque standard de C permet de générer des nombres pseudo-aléatoires grâce à la fonction rand. L'algorithme de génération n'est pas standardisé mais laissé au choix du fournisseur de la bibliothèque. Le C++ n'y a rien changé, mais C++11 va fournir une manière différente de générer les nombres pseudo-aléatoires.

Cette fonctionnalité est découpée en deux parties qui forment un objet de génération de nombres aléatoires :

  • un moteur de génération, qui contient l'état du générateur et produit les nombres pseudo-aléatoires ;
  • une distribution, qui détermine les valeurs que le résultat peut prendre ainsi que sa loi de probabilité.

C++11 définit trois algorithmes de génération, chacun ayant des avantages et des inconvénients.

Template Entier/flottant Qualité Vitesse Taille d'état
linear_congruential Entier Moyenne Moyenne 1
subtract_with_carry Les deux Moyenne Rapide 25
mersenne_twister Entier Bonne Rapide 624

C++11 fournira un certain nombre de lois standard : uniform_int_distribution, bernoulli_distribution, geometric_distribution, poisson_distribution, binomial_distribution, uniform_real_distribution, exponential_distribution, normal_distribution et gamma_distribution.

Le générateur et la distribution se combinent comme dans l'exemple suivant :

std::uniform_int_distribution<int> distribution(0, 99);
std::mt19937 engine;
auto generator = std::bind(distribution, engine);
int random = generator();  // Generate a uniform integral variate between 0 and 99.

Fonctions mathématiques spéciales

Le fichier header <math> définit déjà plusieurs fonctions mathématiques usuelles :

  • trigonométriques : sin, cos, tan, asin, acos, atan, atan2;
  • hyperboliques : sinh, cosh, tanh, asinh, acosh, atanh;
  • exponentielles : exp, exp2, frexp, ldexp, expm1;
  • logarithmiques : log10, log2, logb, ilogb, log1p;
  • puissances : pow, sqrt, cbrt, hypot;
  • spéciales : erf, erfc, tgamma, lgamma.

Le comité a décidé d'ajouter de nouvelles fonctions qui nécessitent actuellement l'utilisation de bibliothèques non-standards. Ces nouvelles fonctions auront un intérêt principalement pour les programmeurs de disciplines scientifiques et pour l'ingénierie.

Le tableau suivant montre les 23 fonctions décrites dans TR1.

Nom de la fonction Prototype de la fonction Expression mathématique
Polynômes de Laguerre généralisés double assoc_laguerre( unsigned n, unsigned m, double x ) ; {L_n}^m(x) = (-1)^m \frac{d^m}{dx^m} L_{n+m}(x), \text{ pour } x \ge 0
Polynômes de Legendre généralisés double assoc_legendre( unsigned l, unsigned m, double x ) ; {P_l}^m(x) = (1-x^2)^{m/2} \frac{d^m}{dx^m} P_l(x), \text{ pour } x \ge 0
Fonction bêta double beta( double x, double y ) ; B(x,y)=\frac{\Gamma(x) \Gamma(y)}{\Gamma(x+y)}
Intégrale elliptique complète de premier genre double comp_ellint_1( double k ) ; K(k) = F\left(k, \textstyle \frac{\pi}{2}\right) = \int_0^{\frac{\pi}{2}} \frac{d\theta}{\sqrt{1 - k^2 \sin^2 \theta}}
Intégrale elliptique complète de deuxième genre double comp_ellint_2( double k ) ; E\left(k, \textstyle \frac{\pi}{2}\right) = \int_0^{\frac{\pi}{2}} \sqrt{1 - k^2 \sin^2 \theta}\; d\theta
Intégrale elliptique complète de troisième genre double comp_ellint_3( double k, double nu ) ; \Pi\left(\nu, k, \textstyle \frac{\pi}{2}\right) = \int_0^{\frac{\pi}{2}} \frac{d\theta}{(1 - \nu \sin^2 \theta)\sqrt{1 - k^2 \sin^2 \theta}}
Fonctions hypergéométriques confluentes double conf_hyperg( double a, double c, double x ) ; F(a, c, x) = \frac{\Gamma(c)}{\Gamma(a)} \sum_{n = 0}^\infty \frac{\Gamma(a + n) x^n}{\Gamma(c + n) n!}
Fonctions de Bessel cylindriques modifiées régulières double cyl_bessel_i( double nu, double x ) ; I_\nu(x) = i^{-\nu} J_\nu(ix) = \sum_{k = 0}^\infty \frac{(x/2)^{\nu + 2k}}{k! \; \Gamma(\nu + k + 1)}, \text{ pour } x \ge 0
Fonctions de Bessel cylindriques du premier genre double cyl_bessel_j( double nu, double x ) ; J_\nu(x) = \sum_{k = 0}^\infty \frac{(-1)^k \; (x/2)^{\nu + 2k}}{k! \; \Gamma(\nu + k + 1)}, \text{ pour } x \ge 0
Fonctions de Bessel cylindriques modifiées irrégulières double cyl_bessel_k( double nu, double x ) ; \begin{align}
K_\nu(x) & = \textstyle\frac{\pi}{2} i^{\nu+1} \big(J_\nu(ix) + i N_\nu(ix)\big) \\
         & = \begin{cases}
                 \displaystyle \frac{I_{-\nu}(x) - I_\nu(x)}{\sin \nu\pi}, & \text{ pour } x \ge 0 \text{ et } \nu \notin \mathbb{Z} \\[10pt]
                 \displaystyle \frac{\pi}{2} \lim_{\mu \to \nu} \frac{I_{-\mu}(x) - I_\mu(x)}{\sin \mu\pi}, & \text{ pour } x < 0 \text{ et } \nu \in \mathbb{Z} \\
             \end{cases}
\end{align}
Fonctions de Neumann cylindriques

Fonctions de Bessel cylindriques du deuxième genre

double cyl_neumann( double nu, double x ) ; 
N_\nu(x) = \begin{cases}
                 \displaystyle \frac{J_\nu(x)\cos \nu\pi - J_{-\nu}(x)}{\sin \nu\pi}, & \text{ pour } x \ge 0 \text{ et } \nu \notin \mathbb{Z} \\[10pt]
                 \displaystyle \lim_{\mu \to \nu} \frac{J_\mu(x)\cos \mu\pi - J_{-\mu}(x)}{\sin \mu\pi}, & \text{ pour } x < 0 \text{ et } \nu \in \mathbb{Z} \\
             \end{cases}
Intégrale elliptique incomplète du premier genre double ellint_1( double k, double phi ) ; F(k,\phi)=\int_0^\phi\frac{d\theta}{\sqrt{1-k^2\sin^2\theta}}, \text{ pour } \left|k\right| \le 1
Intégrale elliptique incomplète du deuxième genre double ellint_2( double k, double phi ) ; \displaystyle E(k,\phi)=\int_0^\phi\sqrt{1-k^2\sin^2\theta}d\theta, \text{ pour } \left|k\right| \le 1
Intégrale elliptique incomplète du troisième genre double ellint_3( double k, double nu, double phi ) ; \Pi(k,\nu,\phi)=\int_0^\phi\frac{d\theta}{\left(1-\nu\sin^2\theta\right)\sqrt{1-k^2\sin^2\theta}}, \text{ pour } \left|k\right| \le 1
Intégrale exponentielle double expint( double x ) ;  \mbox{E}i(x)=-\int_{-x}^{\infty} \frac{e^{-t}}{t}\, dt
Polynômes d'Hermite double hermite( unsigned n, double x ) ; H_n(x)=(-1)^n e^{x^2}\frac{d^n}{dx^n}e^{-x^2}\,\!
Séries hypergéometriques double hyperg( double a, double b, double c, double x ) ; F(a,b,c,x)=\frac{\Gamma(c)}{\Gamma(a)\Gamma(b)}\sum_{n = 0}^\infty\frac{\Gamma(a+n)\Gamma(b+n)}{\Gamma(c+n)}\frac{x^n}{n!}
Polynômes de Laguerre double laguerre( unsigned n, double x ) ; L_n(x)=\frac{e^x}{n!}\frac{d^n}{dx^n}\left(x^n e^{-x}\right), \text{ pour } x \ge 0
Polynômes de Legendre double legendre( unsigned l, double x ) ; P_l(x) = {1 \over 2^l l!} {d^l \over dx^l } (x^2 -1)^l, \text{ pour } \left|x\right| \le 1
Fonction zêta de Riemann double riemann_zeta( double x ) ; 
\Zeta(x) = 
          \begin{cases}
                 \displaystyle \sum_{k = 1}^\infty k^{-x}, & \text{ pour } x > 1 \\[10pt]
                 \displaystyle 2^x\pi^{x-1}\sin\left(\frac{x\pi}{2}\right)\Gamma(1-x)\zeta(1-x), & \text{ pour } x < 1 \\
             \end{cases}
Fonctions sphériques de Bessel du premier genre double sph_bessel( unsigned n, double x ) ; j_n(x) = \sqrt{\frac{\pi}{2x}} J_{n+1/2}(x), \text{ pour } x \ge 0
Fonctions sphériques de Legendre généralisées double sph_legendre( unsigned l, unsigned m, double theta ) ;  Y_{l}^{m}(\theta, 0) \text{ avec } Y_{l}^{m}(\theta, \phi) = (-1)^{m}\left[\frac{(2l+1)}{4\pi}\frac{(l-m)!}{(l+m)!}\right]^{1 \over 2} P_{l}^{m}(cos \theta)e^{im\phi} \text{ pour } |m| \leq l
Fonctions sphériques de Neumann

Fonctions sphériques de Bessel du deuxième genre

double sph_neumann( unsigned n, double x ) ;  n_{n}(x) = \sqrt{\frac{\pi}{2x}} N_{n+1/2}(x) \text{ pour } x \geq 0

Chacune de ces fonctions possède deux variantes supplémentaires. En rajoutant le suffixe ‘f’ ou ‘l’ au nom de la fonction, on obtient les mêmes fonctions agissant sur des float ou des long double respectivement. Par exemple :

float sph_neumannf( unsigned n, float x ) ;
long double sph_neumannl( unsigned n, long double x ) ;

Conversion de références

Conversion polymorphe pour les objets fonctions

Type traits pour la métaprogrammation

Méthode uniforme pour calculer le type de retour des objets fonctions

Notes et références

  1. Blog d'Herb Sutter : March 2010 ISO C++ Standards Meeting
  2. Blog d'Herb Sutter : We have an international standard: C++0x is unanimously approved
  3. Status of Experimental C++0x Support in GCC 4.3 – GNU Project – Free Software Foundation (FSF)
  4. Stroungly Typed Enums (revision 1) : page 9, 'enum-key' est soit 'enum', soit 'enum class', soit 'enum struct'
  5. L'algorithme std::for_each du C++ ne sert qu'à appliquer une fonction à tous les éléments d'une séquence de conteneur (voir la documentation de cette fonction).

Liens externes


Wikimedia Foundation. 2010.

Contenu soumis à la licence CC-BY-SA. Source : Article C++11 de Wikipédia en français (auteurs)

Игры ⚽ Нужно решить контрольную?

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”