Je vous propose trois versions, en ordre chronologique :
J'ai utilisé <type_traits> et std::conditional de C++ 11. |
|
La classe local_buffer<T,N,STATIC_N_BOUNDARY> et sa fonction create() opèrent par valeur, ce qui est efficace même avec un conteneur de grande taille grâce à l'optimisation nommée Copy Elision et, dans le pire des cas, à la sémantique de mouvement. |
|
Un petit programme de test suit, pour montrer que le tout fonctionne bel et bien. |
|
Cette solution, comme la précédente, ne repose que sur des outils standards. |
|
Ce mécanisme très chouette qu'est if constexpr permet de remplacer quelques dizaines de lignes d'effort cérébral par une fonction courte, simple et efficace. |
|
Un petit programme de test suit, pour montrer que le tout fonctionne bel et bien. |
|
Encore une fois, nous nous limiterons à des outils standards. Ce que nous essaierons toutefois de faire est alléger la tâche d'écriture du code client. Vous avez peut-être remarqué que, bien que nous connaissions à la compilation la taille du tampon à créer et le type des éléments à y placer, nous faisons face à deux syntaxes, soit array<T,N>{} pour créer un tableau sans allouer de mémoire dynamiquement (pour un array, il faut que N soit connu à la compilation), et vector<T>(N) pour créer un vecteur et allouer dynamiquement la mémoire pour entreposer des éléments (pour un vector, N peut être connu à l'exécution). |
|
Pour uniformiser la syntaxe dans le cas particulier où N est connu à la compilation, ajoutons une classe dynamic_array<T,N> qui dérivera de vector<T>, et dont le constructeur par défaut appellera le constructeur de vector<T> pour N éléments. Notez l'ajout de using std::vector<T>::vector; pour exposer les constructeurs du parent qui n'auront pas été masqués par l'enfant (donc tous ceux qui ne sont pas le constructeur par défaut). |
|
Nous sommes donc maintenant capables d'ajuster la fonction create_local_buffer<T,N>() pour qu'elle utilise un dynamic_array<T,N>{} au lieu d'un std::vector<T>(N). |
|
La « magie » de CTAD se manifestera grâce à l'alias local_buffer<T,N> qui correspondra au type que retournerait la fonction create_local_buffer<T,N>() si elle était appelée. J'ai choisi de maintenir la fonction create_local_buffer<T,N>(), car il se peut que certain(e)s préfèrent cette écriture, mais elle n'est pas strictement nécessaire, et nous aurions pu l'éliminer puis simplement écrire l'alias local_buffer<T,N> sous la forme suivante : #include <type_traits> template <class T, std::size_t N> using local_buffer = std::conditional_t< (sizeof(T) * N <= 1024 * 4), std::array<T,N>, dynamic_array<T,N> >; |
|
Ceci permet d'écrire le code utilisant local_buffer<T,N> comme s'il s'agissait d'un type tout ce qu'il y a de plus normal. Un petit programme de test suit, pour montrer que le tout fonctionne bel et bien. |
|