Considérez la fonction intégrée suivante:
// Inline specifier version
#include<iostream>
#include<cstdlib>
inline int f(const int x);
inline int f(const int x)
{
return 2*x;
}
int main(int argc, char* argv[])
{
return f(std::atoi(argv[1]));
}
et la version équivalente constexpr:
// Constexpr specifier version
#include<iostream>
#include<cstdlib>
constexpr int f(const int x);
constexpr int f(const int x)
{
return 2*x;
}
int main(int argc, char* argv[])
{
return f(std::atoi(argv[1]));
}
Ma question est: le spécificateur constexpr
implique-t-il le spécificateur inline
dans le sens où si un argument non constant est passé à une fonction constexpr
, le compilateur essaiera de inline
la fonction comme si le spécificateur inline
avait été placé dans sa déclaration?
La norme C++ 11 garantit-elle cela?
Oui ([dcl.constexpr], §7.1.5/2 dans la norme C++ 11): "les fonctions constexpr et les constructeurs constexpr sont implicitement en ligne (7.1.2)."
Notez, cependant, que le spécificateur inline
a réellement très peu (le cas échéant) peu d'effet sur le fait qu'un compilateur est susceptible de développer une fonction en ligne ou non. Cependant, cela affecte la règle de définition unique et de ce point de vue, le compilateur doit suivre les mêmes règles pour une fonction constexpr
qu'une fonction inline
.
Je dois également ajouter que, indépendamment de constexpr
impliquant inline
, les règles pour les fonctions constexpr
en C++ 11 exigeaient qu'elles soient suffisamment simples pour être souvent de bons candidats pour inline l'expansion (la principale exception étant celles qui sont récursives). Depuis lors, cependant, les règles se sont progressivement assouplies, de sorte que constexpr
peut être appliqué à des fonctions beaucoup plus grandes et plus complexes.
constexpr
n'implique pas inline
pour les variables (variables en ligne C++ 17)
Bien que constexpr
implique inline
pour les fonctions, il n'a pas cet effet pour les variables, compte tenu des variables en ligne C++ 17.
Par exemple, si vous prenez l'exemple minimal que j'ai publié sur: Comment fonctionnent les variables en ligne? et supprimez le inline
, en laissant juste constexpr
, alors la variable obtient plusieurs adresses, qui est la principale chose que les variables en ligne évitent.
Exemple minimal que constexpr
implique inline
pour les fonctions
Comme mentionné à: https://stackoverflow.com/a/14391320/895245 le principal effet de inline
n'est pas d'inline mais de permettre plusieurs définitions d'une fonction, citation standard sur : Comment un fichier d'en-tête C++ peut-il inclure l'implémentation?
On peut l'observer en jouant avec l'exemple suivant:
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
assert(shared_func() == notmain_func());
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline int shared_func() { return 42; }
int notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
int notmain_func() {
return shared_func();
}
Compiler et exécuter:
g++ -c -ggdb3 -O0 -Wall -Wextra -std=c++11 -pedantic-errors -o 'notmain.o' 'notmain.cpp'
g++ -c -ggdb3 -O0 -Wall -Wextra -std=c++11 -pedantic-errors -o 'main.o' 'main.cpp'
g++ -ggdb3 -O0 -Wall -Wextra -std=c++11 -pedantic-errors -o 'main.out' notmain.o main.o
./main.out
Si nous supprimons inline
de shared_func
, le lien échouerait avec:
multiple definition of `shared_func()'
car l'en-tête est inclus dans plusieurs .cpp
des dossiers.
Mais si nous remplaçons inline
par constexpr
, alors cela fonctionne à nouveau, car constexpr
implique également inline
.
GCC implémente cela en marquant les symboles comme faibles sur les fichiers objets ELF: Comment un fichier d'en-tête C++ peut-il inclure l'implémentation?
Testé dans GCC 8.3.0.