Comme expliqué dans cette réponse l'instanciation de modèle permet de réduire les temps et les tailles de compilation en ne nécessitant pas la recompilation des modèles pour chaque nouveau type dans chaque nouveau fichier qui les utilise.
Je suis également enthousiasmé par la façon dont modules C++ 2 devrait fournir une solution propre pour exposer les modèles à des projets externes et réduire la duplication hpp/cpp.
Quelle est la syntaxe qui leur permettra de travailler ensemble?
Par exemple, je m'attends à ce que les modules ressemblent un peu à (code non testé et donc probablement erroné car je n'ai pas de compilateur assez nouveau/je ne suis pas sûr qu'il soit encore implémenté):
helloworld.cpp
export module helloworld;
import <iostream>;
template<class T>
export void hello(T t) {
std::cout << t << std::end;
}
helloworld_impl.cpp
export module helloworld_impl;
import helloworld;
// Explicit instantiation
template class hello<int>;
main.cpp
// How to prevent the full definition from being imported here, which would lead
// hello(1) to instantiate a new `hello<int>` instead of reusing the explicit instantiated
// one from `helloworld_impl.cpp`?
import helloworld;
int main() {
hello(1);
}
puis la compilation mentionnée à https://quuxplusone.github.io/blog/2019/11/07/modular-hello-world sera le long (?)
clang++ -std=c++2a -c helloworld.cpp -Xclang -emit-module-interface -o helloworld.pcm
clang++ -std=c++2a -c -fprebuilt-module-path=. -o helloworld_impl.o helloworld_impl.cpp
clang++ -std=c++2a -fprebuilt-module-path=. -o main.out main.cpp helloworld_impl.o
Idéalement, je souhaite également que la définition du modèle soit utilisable sur des projets externes.
Je pense que ce que je veux, c'est un moyen d'importer le module et, au moment de l'importation, de choisir entre:
C'est essentiellement ce que je réalise dans le pré-C++ 20 à "Supprimer les définitions des en-têtes inclus mais aussi exposer les modèles d'une API externe" mais cette configuration nécessite de copier les interfaces deux fois, ce qui semble être quelque chose du module système peut essentiellement faire pour nous.
Les modules rendent le cas de "construction simple rapide" très facile. Ils ne font pas grand-chose pour le cas "support client instanciation mais évitent de reconstruire les clients des spécialisations explicitement instanciées"; la théorie est que les constructions généralement plus rapides évitant le travail répété rend inutile la contorsion du programme afin de gagner encore plus de temps.
Tout ce que vous faites est de mettre une instanciation explicite définition dans l'interface du module:
export module A;
export template<class T>
inline void f(T &t) {++t;}
template void f(int&);
template void f(int*&);
Les importateurs n'auront pas à instancier f
pour l'un ou l'autre de ces deux types, même si le modèle de fonction est en ligne (ce qui peut nécessiter des instanciations supplémentaires en code non modulaire). Une implémentation typique met en cache les résultats de ces instanciations dans le fichier d'interface de module compilé avec suffisamment de détails pour les appels en ligne dans un importateur (ainsi que la mise en cache du modèle lui-même avec suffisamment de détails pour l'instancier davantage).
Vous pouvez bien sûr aussi utiliser une instanciation explicite déclaration avec juste une déclaration du modèle dans l'interface et définir le modèle et mettre des définitions d'instanciation explicite dans une unité d'implémentation de module, mais ce n'est pas différent du fonctionnement des fichiers d'en-tête.