Je peux avoir une définition comme celle-ci dans un fichier d'en-tête?
constexpr double PI=3.14;
Y a-t-il un problème à avoir cela dans un fichier d'en-tête qui serait inclus dans plusieurs fichiers cpp?
Je crains que, car il dit en standard que ce constexpr a sa propre mémoire, en le mettant dans l'en-tête et en ajoutant un en-tête à plusieurs fichiers cpp, générer plusieurs copies de la même valeur en mémoire et d'autres problèmes désagréables.
J'utilise C++ 11
constexpr
implique const
et const
sur la portée globale/namespace implique static
(liaison interne), ce qui signifie que chaque unité de traduction incluant cet en-tête obtient sa propre copie de PI
. La mémoire de cette statique ne sera allouée que si une adresse ou une référence y est prise, et l'adresse sera différente dans chaque unité de traduction.
Cela impliquait static
pour const
variables a été introduit spécifiquement pour utiliser const
au lieu de #define
dans les fichiers d'en-tête en C++ pour définir les constantes. Sans static
, il y aurait définitions de symboles multiples erreur de l'éditeur de liens si ce fichier d'en-tête est inclus dans plusieurs unités de traduction qui ont été liées ensemble.
En C++ 17, vous pouvez également le faire inline
, de sorte qu'il n'y ait qu'une seule copie de PI
si une adresse ou une référence est prise (c'est-à-dire pas static
). Les variables inline
ont été introduites en C++ 17 pour permettre les bibliothèques d'en-tête uniquement avec des définitions de variables non const dans les fichiers d'en-tête. constexpr
sur les membres de données statiques implique inline
, donc inline
n'y est pas nécessaire.
En d'autres termes, vous devez utiliser constexpr
pour vos constantes dans les fichiers d'en-tête, si possible, sinon const
. Et si vous avez besoin que l'adresse de cette constante soit la même partout, marquez-la comme inline
.
Dans C++17
vous êtes clair. Dans C++11
, vous pouvez l'encapsuler dans une fonction:
constexpr double PI () { return 3.14; }
C++ 17 inline
exemple exécutable de variable
Les variables en ligne C++ 17 ont été mentionnées à: tilisation de constexpr dans le fichier d'en-tête et voici un exemple exécutable minimal qui montre qu'un seul emplacement de mémoire est utilisé:
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Compiler et exécuter:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
Le standard C++ garantit que les adresses seront les mêmes. C++ 17 N4659 standard draft 10.1.6 "Le spécificateur en ligne":
6 Une fonction ou variable en ligne avec liaison externe doit avoir la même adresse dans toutes les unités de traduction.
cppreference https://en.cppreference.com/w/cpp/language/inline explique que si static
n'est pas donné, alors il a un lien externe.
Voir aussi: Comment déclarer constexpr extern?
Testé dans GCC 7.4.0, Ubuntu 18.04.
C++ 20 std::math::pi
Notez que pour le cas spécifique de Pi, C++ 20 propose un modèle de variable dédié comme indiqué dans: Comment utiliser la constante PI en C++