Ha senso utilizzare parole chiave inline con i modelli?


119

Poiché i modelli sono definiti all'interno delle intestazioni e il compilatore è in grado di determinare se l'inlining di una funzione è vantaggioso, ha senso? Ho sentito che i compilatori moderni sanno meglio quando incorporare una funzione e ignorano i inlinesuggerimenti.


modifica: vorrei accettare entrambe le risposte, ma non è possibile. Per chiudere la questione accetto la risposta di phresnel , perché ha ricevuto la maggior parte dei voti e ha formalmente ragione, ma come ho detto nei commenti considero corrette anche le risposte di Puppy e Component 10 , da diversi punti di vista .

Il problema è nella semantica C ++, che non è rigorosa in caso di inlineparole chiave e inlining. phresnel dice "scrivi in ​​linea se lo intendi", ma cosa si intende effettivamente con inlinenon è chiaro poiché si è evoluto dal suo significato originale a una direttiva che "impedisce ai compilatori di lamentarsi delle violazioni ODR" come dice Puppy .

Risposte:


96

Non è irrilevante. E no, non tutti i modelli di funzione sono inlinepredefiniti. Lo standard è persino esplicito al riguardo nella specializzazione esplicita ([temp.expl.spec])

Avere quanto segue:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (tratto da Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Compila questo, et voilà:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Anche la mancata affermazione inlinequando si esegue un'istanza esplicita può portare a problemi.

Quindi, in sintesi : per i modelli di funzione non completamente specializzati, cioè quelli che contengono almeno un tipo sconosciuto, è possibile omettere inlinee non ricevere errori, ma ancora non lo sono inline. Per le specializzazioni complete, ovvero quelle che utilizzano solo tipi noti, non è possibile ometterla.

Regola empirica proposta : scrivi inlinese lo intendi e sii coerente. Ti fa pensare meno all'opportunità o meno solo perché puoi. (Questa regola pratica è conforme al modello C ++ di Vandevoorde / Josuttis : The Complete Guide ).


2
Si sarebbe potuto scrivere, vero. Ma ciò non implica l'integrità, anche se sembra così. Vandevoorde e Josuttis affermano esattamente questo anche in C ++ Templates: The complete Guide
Sebastian Mach

43
La specializzazione esplicita non è un modello.
Puppy

2
@DeadMG: Tuttavia, una funzione normale è preferita a una specializzazione completa alla ricerca, quindi se non sono modello, né non modello, cosa sono allora?
Sebastian Mach

13
Questa risposta non è corretta. Una specializzazione esplicita di un modello è una funzione, non un modello. Quella funzione non diventa inlinesolo perché il modello che era specializzato è contrassegnato con inline. Quindi inlinesul modello è completamente irrilevante. Il fatto che quella funzione debba essere inlineo meno non ha nulla a che fare dal fatto che viene generata tramite una specializzazione del modello (e ci sono risposte migliori di questa che indica quando utilizzarla inline). La risposta di @Puppy di seguito è corretta, questa non lo è. L'aggiunta di inlineun modello è irrilevante e clang-tidylo rimuoverà effettivamente.
gnzlbg

6
Inoltre, l'esempio mostra solo i problemi di ODR per le normali funzioni (il comportamento non ha nulla a che fare con i modelli). Per tentare di dimostrare che ciò inlinenon è irrilevante, l'esempio dovrebbe coprire il caso di specializzazione esplicita template<> void f<>(int) {} senza la inlineparola chiave. Ma anche in questo caso la modifica inlinedell'identificatore sul modello non fa alcuna differenza, perché contrassegnare inlineo meno il modello è irrilevante.
gnzlbg

34

È irrilevante. Tutti i modelli lo sono già inline, per non parlare del fatto che a partire dal 2012 l'unico utilizzo della inlineparola chiave è impedire ai compilatori di lamentarsi delle violazioni ODR. Hai assolutamente ragione: il tuo compilatore di generazione corrente saprà cosa inline da solo e probabilmente può farlo anche tra le unità di traduzione.


11
Lo standard non afferma che tutti i modelli sono in linea.
Sebastian Mach

16
@phresnel: ma i modelli hanno la stessa semantica inlinedelle funzioni contrassegnate (ovvero, più definizioni equivalenti possono essere passate al linker, che ne selezionerà una). Questa, non in linea, è la vera funzione della inlineparola chiave.
Ben Voigt

2
@ BenVoigt: Conosco il significato di ODR inline. Forse dai un'occhiata alla mia risposta qui sotto (o sopra, a seconda dell'ordinamento scelto). Per i modelli non specializzati, ovviamente hai ragione, ma formalmente non è la stessa cosa.
Sebastian Mach

3
@DeadMG: non è richiesto in C ++ che un modello di funzione debba essere implementato in un file di intestazione; può essere implementato ovunque. Per riflettere questo, tendo a consigliare di taggare inlineciò che dovrebbe essere in linea. Di solito non fa differenza, ma in standardese non sono uguali e non sono tutti in linea. Accetto la tua posizione al riguardo dicendo "È irrilevante", ma per lo standard, non tutti i modelli sono in linea, solo per te come utente C ++ - appaiono come se.
Sebastian Mach

7
Il tuo commento sulla risposta accettata che la specializzazione esplicita non è un modello (il che è ovvio dopo averlo detto, ovviamente ...) è forse la cosa più utile in questa pagina. Ti dispiacerebbe aggiungerlo anche alla tua risposta?
Kyle Strand

6

Come hai suggerito, inlineè un suggerimento per il compilatore e nient'altro. Può scegliere di ignorarlo o, in effetti, di inline funzioni non contrassegnate inline.

L'utilizzo inlinecon i modelli era un modo (scarso) per aggirare il problema che ogni unità di compilazione avrebbe creato un oggetto separato per la stessa classe basata su modelli che avrebbe quindi causato problemi di duplicazione al momento del collegamento. Usando inline(penso) il nome alterato funziona in modo diverso che aggira lo scontro di nomi al momento del collegamento, ma a scapito di un codice enormemente gonfio.  

Marshall Cline lo spiega qui meglio di me.


@Xeo: non era così. Controlla qui: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/… Presumo che sia cambiato più di recente, ecco perché stavo parlando al passato.
Componente 10

2
@Xeo: puoi indicarmi la parte dello Standard in cui si afferma che i modelli di funzioni sono sempre in linea? Perché non lo sono.
Sebastian Mach

@phresnel: Interessante, potrei giurare di averlo letto nello standard. Forse l'ho confuso con il fatto che i modelli di funzione sono esenti dall'ODR ( §14.5.5.1 p7 & p8). Colpa mia, ho rimosso il commento sbagliato.
Xeo

@Component 10 Perché pensi che sia un modo povero di aggirare il problema della compilation
Kapil
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.