L'auteur du document, dont nous publions la traduction aujourd'hui, dit que le C ++, dans sa forme moderne, par rapport à ce qu'était ce langage il y a plusieurs années, a considérablement changé pour le mieux. Bien sûr, ces changements ne se sont pas produits tout de suite. Par exemple, dans l'ancien temps, C ++ manquait de dynamisme. Ce n'était pas facile de trouver une personne qui pourrait dire qu'il a de tendres sentiments pour cette langue. Tout a changé lorsque les responsables de la normalisation de la langue ont décidé de céder la place aux innovations. En 2011, le C ++ est devenu un langage dynamique, un langage en constante évolution et qui provoque chez les programmeurs des émotions beaucoup plus positives.
Ne pensez pas que la langue est devenue plus facile. Il peut encore être appelé l'un des langages de programmation les plus complexes et les plus utilisés, sinon le plus complexe. Mais le C ++ moderne est devenu beaucoup plus convivial qu'auparavant.

Aujourd'hui, nous allons parler de certaines des nouvelles fonctionnalités du langage (à commencer par C ++ 11, qui, soit dit en passant, a déjà 8 ans), qui seront utiles pour tout programmeur.
Mot-clé automatique
Depuis que le mot clé
auto
est apparu en C ++ 11, la vie des programmeurs est devenue plus facile. Grâce à ce mot-clé, le compilateur peut sortir des types de variables au moment de la compilation, ce qui nous évite d'avoir à toujours spécifier les types nous-mêmes. Cela s'est avéré très pratique, par exemple, dans les cas où vous devez travailler avec des types de données tels que
map<string,vector<pair<int,int>>>
. Lorsque vous utilisez le mot clé
auto
, il y a quelques éléments à considérer. Prenons un exemple:
auto an_int = 26;
Faites attention à la dernière ligne de cet exemple, le commentaire sur lequel est marqué
#1
(ci-après, de manière similaire, nous marquerons les lignes que nous analyserons après les exemples). Il n'y a pas d'initialiseur dans cette ligne, vous ne pouvez pas le faire. Le code situé sur cette ligne empêche le compilateur de savoir quel doit être le type de la variable correspondante.
Initialement, le mot clé
auto
en C ++ était assez limité. Ensuite, dans les versions plus récentes de la langue,
auto
fonctionnalités ajoutées
auto
. Voici un autre exemple:
auto merge(auto a, auto b)
Les lignes
#1
et
#2
appliquent l'initialisation variable à l'aide d'accolades - une autre nouvelle fonctionnalité de C ++ 11.
N'oubliez pas que lors de l'utilisation du mot clé
auto
, le compilateur doit avoir un moyen d'inférer le type de la variable.
Maintenant, une question intéressante. Que se passe-t-il si vous utilisez un modèle comme
auto a = {1, 2, 3}
? Qu'est ce que c'est Vecteur ou cause d'erreur de compilation?
En fait, une construction de la forme
std::initializer_list<type>
est apparue en C ++ 11. La liste entre parenthèses des valeurs d'initialisation sera traitée comme un conteneur à l'aide du mot clé
auto
.
Et enfin, comme déjà mentionné, l'inférence de type par le compilateur peut être extrêmement utile si vous devez travailler avec des structures de données complexes. Voici un exemple:
void populate(auto &data) {
Jetez un oeil à la ligne
#1
. L'expression
auto [v1,v2] = itr.second
représente une nouvelle fonctionnalité de C ++ 17. Il s'agit de la soi-disant décomposition lors de la déclaration de variables. Dans les versions précédentes de la langue, chaque valeur devait être extraite individuellement. Grâce à ce mécanisme, effectuer de telles opérations est devenu beaucoup plus pratique.
De plus, si vous devez travailler avec des données à l'aide de liens, il suffit d'ajouter un seul caractère à cette construction, en le convertissant sous la forme suivante:
auto &[v1,v2] = itr.second
.
Expressions lambda
C ++ 11 introduit la prise en charge des expressions lambda. Ils ressemblent à des fonctions anonymes en JavaScript, ils peuvent être comparés à des objets fonctionnels sans nom. Ils capturent des variables dans différentes portées en fonction de leur description, pour lesquelles des constructions syntaxiques compactes sont utilisées. De plus, ils peuvent être affectés à des variables.
Les expressions lambda sont un outil très utile dans les cas où vous devez effectuer une petite opération dans le code, mais vous ne voulez pas écrire de fonction distincte pour cela. Un autre exemple courant de leur utilisation est la création de fonctions utilisées pour comparer des valeurs. Par exemple:
std::vector<std::pair<int,int>> data = {{1,3}, {7,6}, {12, 4}};
Vous pouvez trouver beaucoup de choses intéressantes dans ce court exemple.
Tout d'abord, faites attention à la commodité d'utiliser l'initialisation variable à l'aide d'accolades. Ensuite, nous pouvons voir les constructions standard
begin()
et
end()
, qui sont également apparues en C ++ 11. Vient ensuite la fonction lambda, qui est utilisée comme mécanisme de comparaison des données. Les paramètres de cette fonction sont déclarés à l'aide du mot
auto
clé
auto
, cette fonctionnalité est apparue en C ++ 14. Auparavant, ce mot-clé ne pouvait pas être utilisé pour décrire les paramètres des fonctions.
Notez maintenant que l'expression lambda commence par des crochets -
[]
. Il s'agit du soi-disant masque de variables. Il détermine la portée de l'expression, c'est-à-dire qu'il vous permet de contrôler la relation de l'expression lambda avec les variables et les objets locaux.
Voici un extrait de
ce référentiel dédié aux fonctionnalités C ++ modernes:
[]
- l'expression ne capture rien. Cela signifie que dans une expression lambda, il est impossible d'utiliser des variables locales à partir de la portée qui lui est externe. Seuls les paramètres peuvent être utilisés dans l'expression.[=]
- l'expression capture les valeurs des objets locaux (c'est-à-dire les variables locales, les paramètres). Cela signifie qu'ils peuvent être utilisés, mais pas modifiés.[&]
- l'expression capture des références à des objets locaux. Ils peuvent être modifiés, comme illustré dans l'exemple suivant.[this]
- l'expression capture la valeur du pointeur this
.[a, &b]
- l'expression capture la valeur de l'objet a
et une référence à l'objet b
.
Par conséquent, si à l'intérieur de la fonction lambda vous avez besoin de convertir les données dans un autre format, vous pouvez utiliser les mécanismes ci-dessus. Prenons un exemple:
std::vector<int> data = {2, 4, 4, 1, 1, 3, 9}; int factor = 7; for_each(begin(data), end(data), [&factor](int &val) {
Ici, si la variable de
factor
était accessible par valeur (alors le masque de variable
[factor]
serait utilisé pour décrire l'expression lambda), alors à la ligne
#1
la valeur de
factor
ne pourrait pas être modifiée - simplement parce que nous n'aurions pas le droit de effectuer une telle opération. Dans cet exemple, nous avons le droit de telles actions. Dans de telles situations, il est important de ne pas abuser des capacités que les variables d'accès fournissent par référence.
De plus, notez que
val
également accessible par référence. Cela garantit que les modifications de données qui se produisent dans la fonction lambda affectent le
vector
.
Expressions d'initialisation variables dans les constructions if et switch
J'ai vraiment aimé cette innovation C ++ 17 juste après l'avoir découverte. Prenons un exemple:
std::set<int> input = {1, 5, 3, 6}; if(auto it = input.find(7); it==input.end()){
Il s'avère que vous pouvez maintenant initialiser les variables et comparer avec leur utilisation dans un bloc
if
ou
switch
. Cela aide à écrire du code précis. Voici une description schématique de la structure considérée:
if( init-statement(x); condition(x)) {
Effectuer des calculs au moment de la compilation à l'aide de constexpr
Le
constexpr
nous offre de grandes opportunités. Supposons que nous ayons une sorte d'expression qui doit être calculée, tandis que sa valeur, après l'avoir initialisée avec la variable correspondante, ne changera pas. Une telle expression peut être calculée à l'avance et utilisée comme macro. Ou, ce qui est devenu possible en C ++ 11, utilisez le
constexpr
.
Les programmeurs s'efforcent de minimiser la quantité de calculs effectués pendant l'exécution du programme. Par conséquent, si certaines opérations peuvent être effectuées pendant le processus de compilation et ainsi supprimer la charge du système pendant l'exécution du programme, cela aura un bon effet sur le comportement du programme pendant l'exécution. Voici un exemple:
#include <iostream> constexpr long long fact(long long n) { // constexpr return n == 1 ? 1 : (fact(n-1) * n); } int main() { const long long bigval = fact(20); std::cout<<bigval<<std::endl; }
Il s'agit d'un exemple très courant d'utilisation de
constexpr
.
Puisque nous avons déclaré la fonction de calcul de la factorielle comme
constexpr
, le compilateur peut pré-calculer la valeur
fact(20)
au moment de la compilation du programme. Par conséquent, après la compilation, la chaîne
const long long bigval = fact(20);
peut être remplacé par
const long long bigval = 2432902008176640000;
.
Notez que l'argument passé à la fonction est représenté par une constante. Il s'agit d'une caractéristique importante de l'utilisation de fonctions déclarées à l'aide du
constexpr
. Les arguments qui leur sont transmis doivent également être déclarés avec le
constexpr
ou avec le mot clé
const
. Sinon, ces fonctions se comporteront comme des fonctions ordinaires, c'est-à-dire que lors de la compilation, leurs valeurs ne seront pas calculées à l'avance.
Les variables peuvent également être déclarées à l'aide du
constexpr
. Dans ce cas, comme vous pouvez le deviner, les valeurs de ces variables doivent être calculées au moment de la compilation. Si cela ne peut pas être fait, un message d'erreur de compilation s'affichera.
Il est intéressant de noter que plus tard, en C ++ 17, les constructions
constexpr-if et
constexpr-lambda sont apparues.
Structures de données de tuple
Comme la structure de données de
pair
, la structure de données de
tuple
(tuple) est une collection de valeurs de différents types d'une taille fixe. Voici un exemple:
auto user_info = std::make_tuple("M", "Chowdhury", 25);
Parfois, au lieu d'une structure de données de
tuple
, il est plus pratique d'utiliser
std::array
. Cette structure de données est similaire aux tableaux simples utilisés dans le langage C, équipés de fonctionnalités supplémentaires de la bibliothèque standard C ++. Cette structure de données est apparue en C ++ 11.
Déduire automatiquement le type d'argument du modèle de classe
Le nom de cette fonctionnalité semble assez long et complexe, mais en fait il n'y a rien de compliqué ici. L'idée principale ici est qu'en C ++ 17, la sortie des types d'arguments de modèle est également effectuée pour les modèles de classe standard. Auparavant, cela n'était pris en charge que pour les modèles fonctionnels. En conséquence, il s'avère qu'ils écrivaient comme ceci:
std::pair<std::string, int> user = {"M", 25};
Avec la sortie de C ++ 17, cette construction peut maintenant être remplacée par ceci:
std::pair user = {"M", 25};
L'inférence de type se fait implicitement. Ce mécanisme est encore plus pratique à utiliser pour les tuples. À savoir, avant de devoir écrire ce qui suit:
std::tuple<std::string, std::string, int> user ("M", "Chy", 25);
Maintenant, la même chose ressemble à ceci:
std::tuple user2("M", "Chy", 25);
Il convient de noter que ces fonctionnalités ne sembleront pas dignes d'attention à ceux qui ne sont pas particulièrement familiers avec les modèles C ++.
Pointeurs intelligents
Travailler avec des pointeurs en C ++ peut être un vrai cauchemar. Grâce à la liberté que donne le langage au programmeur, il lui est parfois très difficile, comme on dit, de "ne pas se tirer une balle dans le pied". Dans de nombreux cas, les pointeurs font pression pour un tel «coup» du programmeur.
Heureusement, C ++ 11 a introduit des pointeurs intelligents qui sont beaucoup plus pratiques que les pointeurs classiques. Ils aident le programmeur à éviter les fuites de mémoire en libérant des ressources lorsque cela est possible. De plus, ils offrent une garantie de sécurité pour les exceptions.
Résumé
Voici un bon référentiel qui, à notre avis, sera intéressant à découvrir par ceux qui suivent les innovations du C ++. Quelque chose de nouveau apparaît constamment dans cette langue. Ici, nous n'avons abordé que quelques caractéristiques modernes de la langue. En fait, il y en a beaucoup. Il est possible que nous en parlions encore.
Chers lecteurs! Quelles fonctionnalités C ++ modernes trouvez-vous les plus intéressantes et utiles?
