Est-il possible de déclarer une variable extern constexpr
et de la définir dans un autre fichier?
Je l'ai essayé mais le compilateur donne une erreur:
La déclaration de la variable
constexpr
'i
' n'est pas une définition
en .h:
extern constexpr int i;
en .cpp:
constexpr int i = 10;
non, vous ne pouvez pas le faire, voici ce que dit la norme (section 7.1.5):
1 Le spécificateur constexpr ne doit être appliqué qu'à la définition d'un variable ou modèle de variable, la déclaration d'une fonction ou modèle de fonction, ou la déclaration d'un membre de données statique d'un type littéral (3.9). Si toute déclaration d'une fonction, fonction template, ou variable template a un spécificateur constexpr, puis tout son les déclarations doivent contenir le spécificateur constexpr. [Note: Une explicite la spécialisation peut différer de la déclaration de modèle en ce qui concerne au spécificateur constexpr. Les paramètres de fonction ne peuvent pas être déclarés constexpr. - note de fin]
quelques exemples donnés par la norme:
constexpr void square(int &x); // OK: declaration
constexpr int bufsz = 1024; // OK: definition
constexpr struct pixel { // error: pixel is a type
int x;
int y;
constexpr pixel(int); // OK: declaration
};
extern constexpr int memsz; // error: not a definition
Non. Extern constexpr n’a aucun sens. Veuillez lire http://fr.cppreference.com/w/cpp/language/constexpr
c'est-à-dire le bit "il doit être immédiatement construit ou recevoir une valeur."
C++ 17 inline
variables
Cette fonctionnalité géniale de C++ 17 nous permet de:
constexpr
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
La norme C++ garantit que les adresses seront les mêmes. Projet de norme C++ 17 N4659 10.1.6 "Le spécificateur en ligne":
6 Une fonction ou une variable en ligne avec une liaison externe doit avoir la même adresse dans toutes les unités de traduction.
cppreference https://fr.cppreference.com/w/cpp/language/inline explique que si static
n'est pas fourni, il est doté d'un lien externe.
Voir aussi: Comment fonctionnent les variables en ligne?
Je suis d'accord avec 'swang' ci-dessus, mais il y a une conséquence. Considérer:
ExternHeader.hpp
extern int e; // Must be extern and defined in .cpp otherwise it is a duplicate symbol.
ExternHeader.cpp
#include "ExternHeader.hpp"
int e = 0;
ConstexprHeader.hpp
int constexpr c = 0; // Must be defined in header since constexpr must be initialized.
Inclure1.hpp
void print1();
Include1.cpp
#include "Include1.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>
void print1() {
std::cout << "1: extern = " << &e << ", constexpr = " << &c << "\n";
}
Inclure2.hpp
void print2();
Include2.cpp
#include "Include2.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>
void print2() {
std::cout << "2: extern = " << &e << ", constexpr = " << &c << "\n";
}
main.cpp
#include <iostream>
#include "Include1.hpp"
#include "Include2.hpp"
int main(int argc, const char * argv[]) {
print1();
print2();
return 0;
}
Quelles impressions:
1: extern = 0x1000020a8, constexpr = 0x100001ed0
2: extern = 0x1000020a8, constexpr = 0x100001ed4
En d'autres termes, constexpr
est alloué deux fois, alors que extern
est alloué une fois . Cela m'est contre-intuitif, car j'attends que constexpr
soit plus optimisé que extern
.
Edit: const
et constexpr
ont le même comportement en ce qui concerne l'allocation. Par conséquent, de ce point de vue, le comportement est celui attendu. Bien que, comme je l'ai dit, j'ai été surpris quand je suis tombé sur le comportement de constexpr
.
Oui il un peu est ...
//===================================================================
// afile.h
#ifndef AFILE
#define AFILE
#include <cstddef>
#include <iostream>
enum class IDs {
id1,
id2,
id3,
END
};
// This is the extern declaration of a **constexpr**, use simply **const**
extern const int ids[std::size_t(IDs::END)];
// These functions will demonstrate its usage
template<int id> void Foo() { std::cout << "I am " << id << std::endl; }
extern void Bar();
#endif // AFILE
//===================================================================
// afile.cpp
#include "afile.h"
// Here we define the consexpr.
// It is **constexpr** in this unit and **const** in all other units
constexpr int ids[std::size_t(IDs::END)] = {
int(IDs::id1),
int(IDs::id2),
int(IDs::id3)
};
// The Bar function demonstrates that ids is really constexpr
void Bar() {
Foo<ids[0] >();
Foo<ids[1] + 123>();
Foo<ids[2] / 2 >();
}
//===================================================================
// bfile.h
#ifndef BFILE
#define BFILE
// These functions will demonstrate usage of constexpr ids in an extern unit
extern void Baz();
extern void Qux();
#endif // BFILE
//===================================================================
// bfile.cpp
#include "afile.h"
// Baz demonstrates that ids is (or works as) an extern field
void Baz() {
for (int i: ids) std::cout << i << ", ";
std::cout << std::endl;
}
// Qux demonstrates that extern ids cannot work as constexpr, though
void Qux() {
#if 0 // changing me to non-0 gives you a compile-time error...
Foo<ids[0]>();
#endif
std::cout << "Qux: 'I don't see ids as consexpr, indeed.'"
<< std::endl;
}
//===================================================================
// main.cpp
#include "afile.h"
#include "bfile.h"
int main(int , char **)
{
Bar();
Baz();
Qux();
return 0;
}
Ce que vous voulez probablement, c’est une initialisation extern et constexpr, par exemple:
// in header
extern const int g_n;
// in cpp
constexpr int g_n = 2;
Ceci est pris en charge dans Visual Studio 2017 uniquement via le mode de conformité: