13

Diciamo che ho il seguente metafunction:Ottimizzazione delle prestazioni a tempo di compilazione da caching METAFUNCTIONS

template <typename T> 
struct make_pair { 
    using type = std::pair< 
     typename std::remove_reference<T>::type, 
     typename std::remove_reference<T>::type 
    >; 
}; 

Sarebbe migliorare la velocità di compilazione per fare questo (o qualcos'altro), invece?

template <typename T> 
struct make_pair { 
    using without_reference = typename std::remove_reference<T>::type; 
    using type = std::pair<without_reference, without_reference>; 
}; 

Vedo due possibilità:

  1. Il compilatore ha a che fare un certo lavoro ogni volta che vede typename std::remove_reference<T>::type. L'uso di un alias intermedio ha un qualche tipo di comportamento di "caching", che consente al compilatore di fare del lavoro una sola volta.

  2. Le prestazioni in fase di compilazione vengono misurate in termini di numero di istanze del modello che il compilatore deve eseguire. Poiché std::remove_reference<T>::type si riferisce allo stesso tipo di std::remove_reference<T>::type, in entrambi i casi è necessaria solo un'istanza di modello, pertanto entrambe le implementazioni sono equivalenti alle prestazioni di compilazione WRT.

Penso che B abbia ragione, ma mi piacerebbe esserne sicuro. Se la risposta risulta essere specifica del compilatore, sarei principalmente interessato a conoscere la risposta per Clang e GCC.

Edit:

I benchmark la compilazione di un programma di test di avere alcuni dati su cui lavorare. Il programma di test fa qualcosa di simile:

template <typename ...> struct result;  

template <typename T> 
struct with_cache { 
    using without_reference = typename std::remove_reference<T>::type; 
    using type = result<without_reference, ..., without_reference>; 
}; 

template <typename T> 
struct without_cache { 
    using type = result< 
     typename std::remove_reference<T>::type, 
     ..., 
     typename std::remove_reference<T>::type 
    >; 
{ }; 

using Result = with[out]_cache<int>::type; 

Questi sono i tempi medi di 10 compilation del programma, con 10 000 parametri di modello in result<>.

   ------------------------- 
       | g++ 4.8 | clang++ 3.2 | 
----------------------------------------- 
| with cache | 0.1628s | 0.3036s  | 
----------------------------------------- 
| without cache | 0.1573s | 0.3785s  | 
----------------------------------------- 

Il programma di test è generato da uno script disponibile here.

+4

Penso che nessuna quantità di speculazione possa sostituire le misurazioni effettive. Si prega di postare alcune cifre temporali, quindi possiamo creare una bella teoria per spiegarle. –

+0

Ho visto un discorso su clang che dice che creano hashtables per le istanze dei template invece degli elenchi collegati. Non so a chi si stessero paragonando. –

+0

Un compilatore 'template' che non esegue la memoizzazione sarà ridicolmente lento. – Yakk

risposta

2

Non posso dire che questo è vero per tutti i compilatori ma GCC, e molto probabilmente ogni altro compilatore importante, userà la memoizzazione. Se ci pensi, è quasi necessario.

Si consideri il seguente codice

&f<X, Y>::some_value == &f<X, Y>::some_value 

Ciò è necessario per essere vero, in modo che il compilatore ha per assicurarsi che non duplica le definizioni dei metodi e membri statici. Ora potrebbero esserci altri modi per farlo, ma questo mi urla solo la memoizzazione; Non vedo un altro modo per implementarlo (concesso, ci ho pensato molto)

Quando uso TMP, mi aspetto che la memoizzazione si verifichi. Sarebbe un vero dolore se non lo facesse, troppo lentamente. L'unico modo in cui ho visto grandi differenze nelle prestazioni in fase di compilazione è a) usando un compilatore più veloce come Clang (che è come 3 volte più veloce di GCC) e scegliendo algoritmi diversi. Piccoli fattori costanti mi sembrano importare ancora meno in TMP di quanto facciano C o C++ nella mia esperienza. Scegli l'algoritmo giusto, cerca di non eseguire il lavoro non necessario, prova a mantenere il numero di istanze giù e usa un buon compilatore (MSVC++ è lento e lontano da C++ 11, ma GCC e Clang sono abbastanza buoni); questo è tutto ciò che puoi fare davvero.

Inoltre, si dovrebbe sempre sacrificare il tempo di compilazione per un codice migliore. L'ottimizzazione prematura del tempo di compilazione è molto più malvagia della semplice ottimizzazione prematura. Ci potrebbe essere un'eccezione a questo se per qualche ragione le prestazioni diventano massicciamente proibitive allo sviluppo; Tuttavia, non ho mai sentito parlare di un caso simile.

+1

Questa risposta non è male, ma non è proprio quello che stavo cercando. Sto cercando qualcosa di più certo come una conferma da uno sviluppatore GCC o Clang. Inoltre, il motivo per cui ho fatto questa domanda è perché ho lavorato sulle librerie di metaprogrammazione e l'ottimizzazione dei tempi di compilazione è cruciale. –

Problemi correlati