Constexpr implica inline?


105

Considera la seguente funzione inline:

// 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]));
}

e la versione equivalente di 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]));
}

La mia domanda è: lo constexprspecificatore implica lo inlinespecificatore nel senso che se un argomento non costante viene passato a una constexprfunzione, il compilatore proverà alla inlinefunzione come se lo inlinespecificatore fosse stato inserito nella sua dichiarazione?

Lo standard C ++ 11 lo garantisce?


5
'[Will] il compilatore proverà ad inline la funzione' non è ciò che fa lo inlinespecificatore. (O forse ho frainteso la tua frase.)
Luc Danton,

5
Lo inlinespecificatore non ha più nulla a che fare con l' inlining
K-ballo

2
La domanda si basa sul presupposto sbagliato che inlineè direttamente correlato all'inlining. Quindi no, lo constexprspecificatore non implica lo inlinespecificatore in quel senso, poiché quel senso non esiste.
Christian Rau

Risposte:


139

Sì ([dcl.constexpr], §7.1.5 / 2 nello standard C ++ 11): "le funzioni constexpr e i costruttori constexpr sono implicitamente inline (7.1.2)."

Si noti, tuttavia, che l' inlineidentificatore ha davvero molto poco (se esiste) effetto su se un compilatore rischia di espandere una funzione inline o meno. Tuttavia, influisce sull'unica regola di definizione e, da quella prospettiva, al compilatore è richiesto di seguire le stesse regole per una constexprfunzione come inlinefunzione.

Dovrei anche aggiungere che, indipendentemente constexprdall'implicazione inline, le regole per le constexprfunzioni in C ++ 11 richiedevano che fossero abbastanza semplici da essere spesso buoni candidati per l'espansione in linea (l'eccezione principale sono quelle ricorsive). Da allora, tuttavia, le regole si sono progressivamente allentate, quindi constexprpossono essere applicate a funzioni sostanzialmente più grandi e complesse.


Dato che l'idea è che le espressioni costanti vengono valutate in fase di compilazione, suppongo che la maggior parte degli usi delle constexprfunzioni non causerà alcuna generazione di codice ...
Kerrek SB

11
Le constexprfunzioni di @KerrekSB vengono potenzialmente valutate in fase di compilazione. Tuttavia lo standard C ++ 14 è disseminato di quelli che molto probabilmente verranno chiamati in fase di esecuzione. Ad esempio:std::array<T,N>::at
Eponimo

@Eponimo sì, ma solo la forma più ridotta rimarrà come opcode. eg: i controlli legati, verranno valutati in fase di compilazione, poiché il loro percorso di codice è const. Ma il valore restituito sarà * (data + offset)
v.oddou

16

constexprnon implica inlineper variabili non statiche (variabili inline C ++ 17)

Sebbene constexprimplichi inlineper le funzioni, non ha quell'effetto per le variabili non statiche, considerando le variabili inline C ++ 17.

Ad esempio, se prendi l'esempio minimo che ho pubblicato su: Come funzionano le variabili in linea? e rimuovi il inline, lasciando solo constexpr, quindi la variabile ottiene più indirizzi, che è la cosa principale che le variabili inline evitano.

constexpr le variabili statiche sono tuttavia implicitamente statiche.

Esempio minimo che constexprimplica inlineper le funzioni

Come accennato in: https://stackoverflow.com/a/14391320/895245 l'effetto principale di inlinenon è quello di inline ma di consentire più definizioni di una funzione, citazione standard su: Come può un file di intestazione C ++ includere l'implementazione?

Possiamo osservarlo giocando con il seguente esempio:

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();
}

Compila ed esegui:

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

Se rimuoviamo inlineda shared_func, il collegamento fallirà con:

multiple definition of `shared_func()'

perché l'intestazione viene inclusa in più .cppfile.

Ma se sostituiamo inlinecon constexpr, allora funziona di nuovo, perché constexprimplica anche inline.

GCC lo implementa contrassegnando i simboli come deboli sui file oggetto ELF: come può un file header C ++ includere l'implementazione?

Testato in GCC 8.3.0.


3
BTW, una variabile membro di una classe statica dichiarata constexprè ancora in linea. cppreference.com : una variabile membro statica (ma non una variabile di ambito dello spazio dei nomi) dichiarata constexprè implicitamente una variabile inline.
anton_rh

@anton_rh grazie, non avevo visto quella regola, aggiorna la risposta.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

non è quello che dice open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0386r0.pdf . dice che constexpr implica inline per le variabili. senza menzione di una differenza tra l'ambito dello spazio dei nomi dell'ambito della classe.
v.oddou
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.