Given the example code segment:
namespace project_namespace::my_math
{
namespace enclosing_namespace = my_math;
struct sphere {};
struct sphere_stuff {
using sphere = enclosing_namespace::sphere;
};
struct line {};
struct line_stuff {
using line = enclosing_namespace::line;
} ;
}
int main()
{
using sphere_stuff = project_namespace::my_math::sphere_stuff;
sphere_stuff::sphere sphere;
using line_stuff = project_namespace::my_math::line_stuff;
line_stuff::line line;
return 0;
}
When I look at the above code, I think to myself:
So my question has two parts:
When the clang and g++ compilers encounter this "namespace enclosing_namespace = my_math", how do they handle this (c++17 and c++20)? In the above segment (if used in a large code base), am I creating a situation where namespaces are copied into namespaces into namespace, etc, a nightmare situation for a compiler? Or is this trivial for a compiler.
Is there some reason why this really shouldn't be done (in 2023, c++17 or c++20)?
Edit: Originally the code used "super_namespace" instead of "enclosing_namespace" - some of the comments below referred to this.
I went and asked over on the llvm issues page, although with a more complicated example.
They provided me with a link to an online compiler which generates an AST dump, and also clarified that basically there is just one node inserted per alias.
The example I provided them was:
namespace project {
namespace enclosing_namespace = project;
namespace namespace_1 {
namespace parent_namespace = project;
namespace enclosing_namespace = namespace_1;
namespace b {
namespace parent_namespace = namespace_1;
namespace enclosing_namespace = b;
struct X {};
struct Y {
using Z = enclosing_namespace::X;
} ;
}
}
namespace namespace_2 {
namespace parent_namespace = project;
namespace enclosing_namespace = namespace_2;
namespace a {
namespace parent_namespace = namespace_2;
namespace enclosing_namespace = a;
struct X {};
struct Y {
using Z = enclosing_namespace::X;
} ;
}
}
}
int main()
{
project::namespace_1::parent_namespace::namespace_2::a::Y::Z z;
return 0;
}
And the dump looks like this:
TranslationUnitDecl
|-NamespaceDecl <line:1:1, line:33:1> line:1:11 project
| |-NamespaceAliasDecl <line:2:5, col:37> col:15 enclosing_namespace
| | `-Namespace 'project'
| |-NamespaceDecl <line:4:5, line:17:5> line:4:15 namespace_1
| | |-NamespaceAliasDecl <line:5:9, col:38> col:19 parent_namespace
| | | `-Namespace 'project'
| | |-NamespaceAliasDecl <line:6:9, col:41> col:19 enclosing_namespace
| | | `-Namespace 'namespace_1'
| | `-NamespaceDecl <line:8:9, line:16:9> line:8:19 b
| | |-NamespaceAliasDecl <line:9:13, col:42> col:23 parent_namespace
| | | `-Namespace 'namespace_1'
| | |-NamespaceAliasDecl <line:10:13, col:45> col:23 enclosing_namespace
| | | `-Namespace 'b'
| | |-CXXRecordDecl <line:12:13, col:23> col:20 referenced struct X definition
| | | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | | | |-MoveConstructor exists simple trivial needs_implicit
| | | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | | | |-MoveAssignment exists simple trivial needs_implicit
| | | | `-Destructor simple irrelevant trivial needs_implicit
| | | `-CXXRecordDecl <col:13, col:20> col:20 implicit struct X
| | `-CXXRecordDecl <line:13:13, line:15:13> line:13:20 struct Y definition
| | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveConstructor exists simple trivial needs_implicit
| | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveAssignment exists simple trivial needs_implicit
| | | `-Destructor simple irrelevant trivial needs_implicit
| | |-CXXRecordDecl <col:13, col:20> col:20 implicit struct Y
| | `-TypeAliasDecl <line:14:17, col:48> col:23 Z 'enclosing_namespace::X':'project::namespace_1::b::X'
| | `-ElaboratedType 'enclosing_namespace::X' sugar
| | `-RecordType 'project::namespace_1::b::X'
| | `-CXXRecord 'X'
| `-NamespaceDecl <line:19:5, line:32:5> line:19:15 namespace_2
| |-NamespaceAliasDecl <line:20:9, col:38> col:19 parent_namespace
| | `-Namespace 'project'
| |-NamespaceAliasDecl <line:21:9, col:41> col:19 enclosing_namespace
| | `-Namespace 'namespace_2'
| `-NamespaceDecl <line:23:9, line:31:9> line:23:19 a
| |-NamespaceAliasDecl <line:24:13, col:42> col:23 parent_namespace
| | `-Namespace 'namespace_2'
| |-NamespaceAliasDecl <line:25:13, col:45> col:23 enclosing_namespace
| | `-Namespace 'a'
| |-CXXRecordDecl <line:27:13, col:23> col:20 referenced struct X definition
| | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
| | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param
| | | |-MoveConstructor exists simple trivial
| | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | | |-MoveAssignment exists simple trivial needs_implicit
| | | `-Destructor simple irrelevant trivial needs_implicit
| | |-CXXRecordDecl <col:13, col:20> col:20 implicit struct X
| | |-CXXConstructorDecl <col:20> col:20 implicit used constexpr X 'void () noexcept' inline default trivial
| | | `-CompoundStmt <col:20>
| | |-CXXConstructorDecl <col:20> col:20 implicit constexpr X 'void (const X &)' inline default trivial noexcept-unevaluated 0xbb9e218
| | | `-ParmVarDecl <col:20> col:20 'const X &'
| | `-CXXConstructorDecl <col:20> col:20 implicit constexpr X 'void (X &&)' inline default trivial noexcept-unevaluated 0xbb9e418
| | `-ParmVarDecl <col:20> col:20 'X &&'
| `-CXXRecordDecl <line:28:13, line:30:13> line:28:20 struct Y definition
| |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr
| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveConstructor exists simple trivial needs_implicit
| | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveAssignment exists simple trivial needs_implicit
| | `-Destructor simple irrelevant trivial needs_implicit
| |-CXXRecordDecl <col:13, col:20> col:20 implicit struct Y
| `-TypeAliasDecl <line:29:17, col:48> col:23 referenced Z 'enclosing_namespace::X':'project::namespace_2::a::X'
| `-ElaboratedType 'enclosing_namespace::X' sugar
| `-RecordType 'project::namespace_2::a::X'
| `-CXXRecord 'X'
`-FunctionDecl <line:35:1, line:40:1> line:35:5 main 'int ()'
`-CompoundStmt <line:36:1, line:40:1>
|-DeclStmt <line:37:5, col:67>
| `-VarDecl <col:5, col:66> col:66 z 'project::namespace_1::parent_namespace::namespace_2::a::Y::Z':'project::namespace_2::a::X' callinit
| `-CXXConstructExpr <col:66> 'project::namespace_1::parent_namespace::namespace_2::a::Y::Z':'project::namespace_2::a::X' 'void () noexcept'
`-ReturnStmt <line:39:5, col:12>
`-IntegerLiteral <col:12> 'int' 0
You can also play with the online compiler here: https://godbolt.org/z/G4beW7YnP
So it seems that creating these namespace aliases is almost free.