web-dev-qa-db-fra.com

utilisation de constexpr dans le fichier d'en-tête

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

20
mans

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.

35
Maxim Egorushkin

Dans C++17 vous êtes clair. Dans C++11, vous pouvez l'encapsuler dans une fonction:

constexpr double PI () { return 3.14; }
6
KevinZ

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(&notmain_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 &notmain_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

GitHub en amont .

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