| Document #: | P4370R0 |
| Date: | 2026-09-10 |
| Project: | Programming Language C++ |
| Audience: |
Core Language Evolution Group |
| Reply-to: |
Chuanqi Xu <chuanqi.xcq@alibaba-inc.com> |
Currently, the module implementation units will import the primary module interface implicitly.
[module.unit]p8:
A module-declaration that contains neither an export-keyword nor a module-partition implicitly imports the primary module interface unit of the module as if by a module-import-declaration.
And the primary module interface is required to import all interfaces units in the module.
[module.unit]p3:
All module partitions of a module that are module interface units shall be directly or indirectly exported by the primary module interface unit ([module.import]). No diagnostic is required for a violation of these rules.
So that, now the standard requires the module implementation units depends on all the interface units in the module.
For example,
No matter if m1.cpp or m2.cpp depends on m:interfaceA and m:interfaceB or not, when m-interfaceA.cppm or m-interfaceB.cppm are touched, both m1.cpp and m2.cpp will be recompiled.
THIS IS EXTREMELLY A WASTE OF TIME IN PRACTICE. Especially when the number of module partitions grow up.
Do not ask the module implementation units to import the primary module interface implicitly.
This is a breaking change. But the current user who don’t want this
If we’re afraid this as a breaking change, we can introduce a new syntax,
where explicit can only appear in front of a module implementation unit. Then the explicit module implementation unit won’t import the primary module interface unit implicitly.
Actually we have a standard conforming workaround for this issue. That is to use the module internal partition units as module implementation units. e.g.,
then the users can control the dependencies much more precisely.
This works perfectly fine in our downstream projects. But there are two problems which makes me to write the proposal, one practical and one abstract:
Except our internal codebase, there aleady open source code base using this pattern now.
infinity is a business project using C++20 modules natively. Now it has 884 internal partition units which follows the pattern as *.impl.
Another workaround is to not use partitions. But what if we do need the partition semantics?
Users use dot to mimic it. For the above example,
So that the false dependency is cut.
There also projects using this tricks.
The cost is that the complete module name became unnecessarily long. For example,
tm.team_predictor.ev_optimizer.possible_optimized_ivscontainers.algorithms.sort.merge_relocate_second_rangeredi.util.concepts.unambiguous_implicit_functormdux.tools.verify.medui_evidenceAnd also this makes the concept of partitions not useful.
The other practices shows that this is a real need to fix real problems.
I don’t think we can say “oh, the users simply don’t understand modules and they didn’t make the hierarchy well.”