3

I am trying to expose a c++ namespace to whatever includes that c++ module. Usually in a header file I can just write using namespace x::y::z; and it'll work. I couldn't get it to work from a module.

I am using visual studio 2022 with MSVC v143, c++ latest.

cclaid
  • 33
  • 3
  • 2
    note that it is considered bad practice to use namespaces in a header. See here for a famous example: [Why is “using namespace std;” considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). Usually its fine in a source file but can cause issues in a header – 463035818_is_not_an_ai Jun 23 '22 at 09:30
  • i am aware of that, however the math library i am using "linalg" requires me to type `linalg::aliases::float3`, that's pretty inconvenient and i don't see an issue exposing `linalg::aliases` here when importing math.linalg in this case. – cclaid Jun 23 '22 at 09:32
  • if you are aware of the implications then it is of course fine, though as you see no issue, I am afraid you are not aware of the implications ;). Anyhow, its a completely valid question. – 463035818_is_not_an_ai Jun 23 '22 at 09:35
  • So what exactly did you try with the module? Just `export module A; using namespace x::y::z;` or something else? – Useless Jun 23 '22 at 09:37
  • yes, using `namespace x::y::z` after export module. – cclaid Jun 23 '22 at 09:56
  • 1
    Short answer: You can't export `using namespace...` declarations. Longer answer (from [reddit](https://www.reddit.com/r/cpp_questions/comments/nws8jt/c20_modules_export_using_namespace/h1by8mt/)): Only named entities can be exported, and similar to static_asserts, even though using namespace declarations are declarations, they don't name anything. – Adrian Mole Jun 23 '22 at 10:07
  • You may be able to export a namespace alias though, or direct aliases for the type(s) you want to introduce. – Useless Jun 23 '22 at 10:12
  • @Scheff'sCat I'm not sure I'd be adding anything substantial to the reddit post. It would be paramount to plagiarism. – Adrian Mole Jun 23 '22 at 10:21
  • In your own (application's namespace) just create a short name space alias eg `namespace la = linalg::aliases;` . As this is in your application's namespace it will not pollute the global namespace. There is a post here somewhere (looking for it) that describes the global (top-level) namespace as _"the wild west"_ and agues for never using it but to always create an application namespace. – Richard Critten Jun 23 '22 at 10:28
  • To provide a good answer to this question first we should know: WHY? More context is needed! – Marek R Jun 23 '22 at 11:27

2 Answers2

6

In the current standard draft § 10.2 [module.interface], we see:

export using namespace N;        // error: does not declare a name

In the same section, there are also correct exports of non-namespace using declarations

export using T = S;              // OK, exports name T denoting type S

and I believe that namespace aliases should also work

export namespace N = M;

The distinction is that the using namespace directive provides a tunnel for unqualified lookup to search outside its natural scope, but doesn't declare any new names. Both using declarations and namespace aliases do declare new names, and those names should be exportable.

Concretely, either of these should work:

export using float3 = linalg::aliases::float3; // for each type
export namespace la = linalg::aliases;         // or just provide a short name
Useless
  • 64,155
  • 6
  • 88
  • 132
1

The rule here changed (even in C++20 modes) via CWG2443, such that you can write

export using namespace …;

in a module with the obvious effect. (Note that a using-directive in a module interface unit already affected ordinary module units of the same module.)

Of course. this shouldn’t be considered the default way of doing things; it’s quite helpful that a using-directive can be used in a module for local readability without affecting its clients.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • Yes, I am finding that msvc (VS 17.7.2) accepts `export using namespace …;` . I agree that it shouldn't be the default modus operandi, however when purposefully exporting a type alias, the need to ensure that the module client sees any namespace that the exported alias depends upon, arises. (Your answer here is astute). – Coder Aug 28 '23 at 21:30
  • 1
    @Coder: You **don’t** need to export anything just because a type alias refers to it. “Dereferencing” a type alias is not name lookup and thus does not depend on `export` (of anything). – Davis Herring Aug 29 '23 at 02:03
  • @Coder: I’m not sure what “as if it were defined in the imported module” means—the type is just the type, and (say) `.f()` on it means what it always does. (It might be incomplete depending on how it’s declared in the owning module, for instance, but it’s not _automatically_ incomplete as if only non-defining declarations could be made available this way.) – Davis Herring Aug 29 '23 at 04:15
  • I have an example of this nature: Module X has exported class X and also has class X2 in a non-exported namespace. Class X returns an instance of class X2 from function ret_X2( ). Module Y imports module X and has using test_x = X; Module Y also calls text_x.ret_X2() and is able to use the return value which is an instance of X2 even though X2 is in a non-exported namespace in Module X (it compiles). So, I don't expect to be able to even experiment with an `export using` example because I wouldn't expect that Module Y could use class X2 because it's not even exported (compiler bugs?). – Coder Aug 29 '23 at 05:58
  • @Coder: Exporting affects name lookup (and, as necessary, linkage) **only**. What would the `test_x::ret_X2()` line even _mean_ if "Module Y could[n't] use class X2 because it's not even exported"? `test_x` is a type and you can use that type. Period. – Davis Herring Aug 29 '23 at 07:02
  • In experimenting, in module Y: If I place the returned X2 instance in a variable using auto as the variable type, it compiles and runs. However, if I use ns_of_X2::X2 instead of auto as the variable type, the compilation fails saying that X2 is not a member of ns_of_X2. Hovering over the auto that does compile, shows ns_of_X2::X2 as the variable type, yet declaring the variable using that same type name, fails. – Coder Aug 30 '23 at 01:27
  • @Coder: OK…? That is its name, but it’s not exported so you can’t use it to refer to the type (even though you can use the type itself and all its (complete) subcomponents). – Davis Herring Aug 30 '23 at 01:59
  • OK. I also find that additional instances, of the non-exported type (even in anonymous namespace), can be declared in an external module by using decltype on the returned instance. ("visibility" vs. " reachability") I'm not aware of any valuable use cases for this behavior but I do see value in knowing that if I don't export something (especially if it's an anonymous namespace) that it cannot be used/accessed in any way by an external TU. However, I see that is not the case. Thank you, and if you do know of an example use case, and would like to share it, please do. – Coder Aug 30 '23 at 05:53
  • I tried to move this discussion to chat. It [worked (partly)](https://chat.stackoverflow.com/rooms/255101/discussion-between-coder-and-davis-herring), but didn't seem to produce a notification here. – Davis Herring Sep 01 '23 at 20:47