2023-07-31 09:16:00
Il y a plus dans le langage de base C++23 que de déduire cela. Aujourd’hui, je vais écrire sur les petites perles.
Publicité
Rainer Grimm travaille depuis de nombreuses années en tant qu’architecte logiciel, chef d’équipe et responsable de la formation. Il aime écrire des articles sur les langages de programmation C++, Python et Haskell, mais aime aussi intervenir fréquemment lors de conférences spécialisées. Sur son blog Modernes C++, il traite intensément de sa passion pour le C++.
Suffixes littéraux
C++23 fournit de nouveaux suffixes littéraux intégraux pour (signé) std::size_t
un.
std :: taille_t (C++17) est un type de données non signé qui peut contenir la taille maximale de n’importe quel type. Il est souvent utilisé pour indexer des tableaux et compter dans des boucles.
Un exemple d’utilisation consiste à parcourir un vecteur. Pour des raisons d’optimisation, sa taille est stockée dans le cache.
Publicité
#include
int main() {
std::vector v{0, 1, 2, 3};
for (auto i = 0, s = v.size(); i < s; ++i) {
/* use both i and v[i] */
}
}
Lors de la compilation, le message d'erreur suivant apparaît Explorateur de compilateur:
la raison en est auto i
dans int
et s
dans long unsigned int
dérivé. Par conséquent, le problème n'est pas résolu même si les deux variables ne sont pas signées.
#include
int main() {
std::vector v{0, 1, 2, 3};
for (auto i = 0u, s = v.size(); i < s; ++i) {
/* use both i and v[i] */
}
}
Maintenant, le compilateur dirige i
pour unsigned int
mais s
pour long unsigned int
loin. La capture d'écran suivante montre à nouveau la sortie d'erreur de l'explorateur du compilateur.
C++23 corrige ce problème avec le nouveau suffixe littéral z
.
#include
int main() {
std::vector v{0, 1, 2, 3};
for (auto i = 0uz, s = v.size(); i < s; ++i) {
/* use both i and v[i] */
}
}
Cet exemple est basé sur la proposition P0330R8. Il comprend des exemples plus motivants des nouveaux suffixes littéraux.
if consteval
if consteval
se comporte comme if (std::is_constant_evaluated()) { }
mais présente quelques avantages :
- Il n'y aura pas d'en-tête
nécessaire. - Il a une syntaxe plus simple que
std::is_constant_evaluated.
- Il peut être utilisé pour exécuter des fonctions immédiates (
consteval
les fonctions).
std::is_constant_evaluated
est une fonction C++20 qui détecte si un constexpr
La fonction est exécutée pendant la compilation.
Sur cppreference.com/is_constant_evaluated voici un excellent exemple :
#include
#include
#include
constexpr double power(double b, int x)
{
if (std::is_constant_evaluated() && !(b == 0.0 && x < 0))
{
// A constant-evaluation context:
// Use a constexpr-friendly algorithm.
if (x == 0)
return 1.0;
double r {1.0};
double p {x > 0 ? b : 1.0 / b};
for (auto u = unsigned(x > 0 ? x : -x); u != 0; u /= 2)
{
if (u & 1)
r *= p;
p *= p;
}
return r;
}
else
{
// Let the code generator figure it out.
return std::pow(b, double(x));
}
}
int main()
{
// A constant-expression context
constexpr double kilo = power(10.0, 3);
int n = 3;
// Not a constant expression, because n cannot be
// converted to an rvalue
// in a constant-expression context
// Equivalent to std::pow(10.0, double(n))
double mucho = power(10.0, n);
std::cout << kilo << " " << mucho << "n"; // (3)
}
La fonction power
est constexpr
. Cela signifie qu'il peut être exécuté au moment de la compilation. Le premier appel de power
provoque l'exécution à la compilation car le résultat est demandé à la compilation : constexpr double kilo = power(10.0, 1).
Le deuxième appel, en revanche, ne peut être exécuté qu'à l'exécution car l'argument de la fonction n
n'est pas une expression constante : double mucho = power(10.0, n).
Humide std::is_constant_evaluated
un code différent est exécuté à la compilation et à l'exécution. Au moment de la compilation, le if-
Exécuté et à l'exécution la branche else
-Bifurquer. Les deux power
Les vues totalisent 1000.
Une fonction immédiate est une consteval
-Fonction. Un consteval
-Function est une fonction qui ne peut être exécutée qu'au moment de la compilation. Plus à propos consteval
-Functions est dans mon post C++20 : Deux nouveaux mots clés en C++20 : consteval et constinit.
Basé sur consteval if
laisse toi std::is_constant_evaluated
implémenter:
constexpr bool is_constant_evaluated() {
if consteval {
return true;
} else {
return false;
}
}
auto(x)
et auto{y}
Un moyen générique d'obtenir une copie d'un objet en C++ est auto copy = x
;. Cela fonctionne mais a un problème: copy
est une lvalue, mais parfois vous voulez une prvalue. prvalue est l'abréviation de pure rvalue. Une rvalue pure est une expression dont l'évaluation initialise un objet. Pour en savoir plus sur les catégories de valeur, consultez le post de Barry : Catégories de valeurs en C++17.
Les vues auto(x)
et auto{x}
convertir x en prvalue comme s'ils x
serait passé comme argument de fonction par valeur. auto(x)
et auto{x}
conduire un copie de décomposition à travers.
Dans mes cours de formation, on me demande souvent ce que signifie la décomposition. Je voudrais donc l'expliquer plus en détail. Decay signifie essentiellement que certaines informations de type sont perdues lors de la copie d'une valeur. Un exemple typique est une fonction qui prend son argument comme valeur. Voici les différents types de caries :
- Conversion de tableau en pointeur
- Conversion de fonction en pointeur
- Jeter de
const/volatile
Qualificatif - Suppression de références
Le programme suivant montre les quatre types de désintégrations :
// decay.cpp
void decay(int*, void(*)(int), int, int ) { } // (5)
void func(int){} // (2)
int main() {
int intArray[5]{1, 2, 3, 4, 5}; // (1)
const int myInt{5}; // (3)
const int& myIntRef = myInt; // (4)
decay(intArray, func, myInt, myIntRef);
}
La fonction decay
(5) a besoin d'un pointeur vers un int
un pointeur de fonction et deux int
s. Le premier argument de l'appel de fonction est un int
-Array(1), le deuxième une fonction(2), le troisième une const int
(3) et le dernier est un const int&
(4).
La bibliothèque de traits de type a la fonction std :: pourriture. Avec cette fonction, vous pouvez le faire carie appliquer directement à un type. En conséquence, ce sont les conversions de type correspondantes avec std::decay
.
// decayType.cpp
#include
int main() {
// (1)
// int[5] -> int*
static_assert(std::is_same::type,
int*>::value);
// (2)
// void(int) -> void(*)(int)
static_assert(std::is_same::type,
void(*)(int)>::value);
// (3)
// const int -> int
static_assert(std::is_same::type,
int>::value);
// (4)
// const int& -> int
static_assert(std::is_same::type,
int>::value);
}
Et après?
Il existe d'autres petits joyaux en C++23. Dans mon prochain article, je poursuivrai mon voyage avec plus de fonctionnalités de langage de base de C++23.
(rme)
#C23 #les #petites #perles #langage #base
1690949347