web-dev-qa-db-fra.com

Constexpr implique-t-il en ligne?

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?

82
Vincent

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.

122
Jerry Coffin

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.