Date: Mon, 6 Apr 2020 11:32:31 -0400
On Mon, Apr 6, 2020 at 8:46 AM Michał Policht via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>
> > I think the main purpose of a struct is not name scoping.
>
> It is one of its characteristics.
>
When used strictly for namespacing purposes, I think the main difference is
"namespaces are open for additions; structs are closed against additions."
FWIW, John Lakos' *Large Scale C++, Volume 1* advocates structs over nested
namespaces, and says the following:
(Figure 2-23, page 316)
There are many advantages of using a struct over a third level of namespace
for aggregating related (what would otherwise be *free*) functions into a
single *utility* component.
(1) The distinct syntax and atomic nature of a struct having static methods
makes its purpose as a component-scoped entity clearer than would yet
another, nested namespace, leaving namespaces for routine use at the
package and enterprise levels exclusively.
(2) The self-declaring nature of functions and data defined at namespace
scope are necessarily eliminated when they are instead nested (as static
members) within a struct.
(3) Unlike a namespace, a struct does not permit using directives (or
declarations) to import function names into the current (e.g. package)
namespace, thereby preventing any consequent loss in readability.
(4) Unlike a namespace, a struct can support private nested data — e.g. as
an optimization for accessing insulated (external bindage) table-based
implementation details, residing in the .cpp file, by one or more inline
functions, residing in the .h file.
(5) Unlike a namespace, a struct can be passed as a template parameter —
e.g. as a cartridge of related functions satisfying a concept.
(6) Unlike a namespace, a C-style function in a struct does not participate
in Argument-Dependent Lookup (ADL), thereby avoiding potentially large
overload sets, which could needlessly affect compile-time performance and
possibly introduce unanticipated (perhaps even latent) ambiguity, or — much
worse — invoke the wrong function. By placing our "free" functions in a
struct, we make our design decision not to employ ADL explicit.
(7) Except for a few very stylized cases, such as std::placeholders (e.g.
_1, _2, _3) and std::literals, use of namespace declarations are generally
ill-advised. Should we subsequently discover a rare valid engineering
reason for enabling local using declarations, we can easily migrate a
struct to a namespace by creating a new component-private struct, e.g.
MathUtil_Imp, and forwarding calls to it from the new nested (e.g.
MathUtil) namespace. Note that, except when used as in (5), it is always
possible to migrate from a struct to a namespace without forcing any
clients to rework their source code, but, given the possibility of using
directives/declarations, not vice versa.
–Arthur
std-proposals_at_[hidden]> wrote:
>
> > I think the main purpose of a struct is not name scoping.
>
> It is one of its characteristics.
>
When used strictly for namespacing purposes, I think the main difference is
"namespaces are open for additions; structs are closed against additions."
FWIW, John Lakos' *Large Scale C++, Volume 1* advocates structs over nested
namespaces, and says the following:
(Figure 2-23, page 316)
There are many advantages of using a struct over a third level of namespace
for aggregating related (what would otherwise be *free*) functions into a
single *utility* component.
(1) The distinct syntax and atomic nature of a struct having static methods
makes its purpose as a component-scoped entity clearer than would yet
another, nested namespace, leaving namespaces for routine use at the
package and enterprise levels exclusively.
(2) The self-declaring nature of functions and data defined at namespace
scope are necessarily eliminated when they are instead nested (as static
members) within a struct.
(3) Unlike a namespace, a struct does not permit using directives (or
declarations) to import function names into the current (e.g. package)
namespace, thereby preventing any consequent loss in readability.
(4) Unlike a namespace, a struct can support private nested data — e.g. as
an optimization for accessing insulated (external bindage) table-based
implementation details, residing in the .cpp file, by one or more inline
functions, residing in the .h file.
(5) Unlike a namespace, a struct can be passed as a template parameter —
e.g. as a cartridge of related functions satisfying a concept.
(6) Unlike a namespace, a C-style function in a struct does not participate
in Argument-Dependent Lookup (ADL), thereby avoiding potentially large
overload sets, which could needlessly affect compile-time performance and
possibly introduce unanticipated (perhaps even latent) ambiguity, or — much
worse — invoke the wrong function. By placing our "free" functions in a
struct, we make our design decision not to employ ADL explicit.
(7) Except for a few very stylized cases, such as std::placeholders (e.g.
_1, _2, _3) and std::literals, use of namespace declarations are generally
ill-advised. Should we subsequently discover a rare valid engineering
reason for enabling local using declarations, we can easily migrate a
struct to a namespace by creating a new component-private struct, e.g.
MathUtil_Imp, and forwarding calls to it from the new nested (e.g.
MathUtil) namespace. Note that, except when used as in (5), it is always
possible to migrate from a struct to a namespace without forcing any
clients to rework their source code, but, given the possibility of using
directives/declarations, not vice versa.
–Arthur
Received on 2020-04-06 10:35:40