0

Everytime I write a header I end up doing something like this:

#ifndef D723E2D5_1943_4166_87CC_73F5C9C47544
#define D723E2D5_1943_4166_87CC_73F5C9C47544
#include "RandomIntegers.hpp"
...
#include "IRenderer.hpp"

namespace Pathfinding::Core { class ApplicationBuilder; }
namespace Pathfinding::Datastructures { struct Node; }

namespace Pathfinding::Core
{
    class Application final : public Pathfinding::Abstract::IApplication
    {
        friend Pathfinding::Core::ApplicationBuilder;
    private:
        using PAIMenu = Pathfinding::Abstract::IMenu;
        using PAIEventManager = Pathfinding::Abstract::IEventManager;
        using PAAIncrementalInformedAlgorithm = Pathfinding::Abstract::AIncrementalInformedAlgorithm;
        using PAIGraphOperations = Pathfinding::Abstract::IGraphOperations;
        using PCApplicationState = Pathfinding::Core::ApplicationState;
        using PAALatGraphWr = Pathfinding::Abstract::ALatGraphWr;
        using PAIAStar = Pathfinding::Abstract::IAStar;
        using PDPathfinderCachee = Pathfinding::Datastructures::PathfinderCache;
        using PEMouseData = Pathfinding::Events::MouseData;
        using PEBindingsContainer = Pathfinding::Events::BindingsContainer;
        using PRDrawablePath = Pathfinding::Rendering::DrawablePath;
        using PDNode = Pathfinding::Datastructures::Node;
        using PADSFMazeGenerator = Pathfinding::Algorithms::DFSMazeGenerator;
        using PRNodeStateColors = Pathfinding::Rendering::NodeStateColors;
        using PAIFontLoader = Pathfinding::Abstract::IFontLoader;
        using PRGradientChanger = Pathfinding::Rendering::GradientChanger;
        using PAIRenderer = Pathfinding::Abstract::IRenderer;

    public:
     ...
    private:
        std::unique_ptr<PAIMenu> menuUPtr = nullptr;
        ...
        PEBindingsContainer bindings;
    };
}

#endif /* D723E2D5_1943_4166_87CC_73F5C9C47544 */

but I am not sure about the using stuff, is there a better way or is this acceptable? I am sure its better than using namespace, using Foo::Bar::Class is also not recomended at namespace scope as far as I know, so what other alternatives are there then?

PS: I found a similar question, but its eight years old, some maybe there is something new.
What are the good practices for including namespaces in C++ that avoid more typing?

2
  • Entirely unrelated: Ever heard of #pragma once?
    – tofro
    Mar 30, 2022 at 23:01
  • @tofro, I heard about that, but last time I researched this topic was a few years back and at that time, not all compilers supported pragma once. I googled a few things again, and it seems that now most of major compilors support pragma, but its still not standard and it has few a downsides(see wiki). I won't use them for three reasons, 1: not standard, 2: I have a plugin which generate guards for me, so no possibility for a typo, 3: no other Advantages. They should be slightly faster in some cases but, don't know, isn't really that important to me, at least now.
    – a a
    Mar 31, 2022 at 9:24

1 Answer 1

1

The using keyword has different roles.

A type alias or namespace alias using NewName = OldName or using Qualified::Name or namespace NewName = OldName is just better syntax for a typedef or for #define macros and is perfectly acceptable. It has no substantial negative effects. Do use this if it increases readability of your code, especially if it helps you to avoid deeply nested qualified identifiers Foo::Bar::Baz.

This is entirely different from the using namespace Foo using-directive. This introduces every name from that namespace into the current scope. Sometimes this is appropriate, in particular for convenience or due to the rules on argument-dependent lookup, but at least in headers that is a very bad practice. That is what your linked question is about. A using namespace in a header file is prohibited by the C++ Core Guidelines rule SF.7, but accepted in local scopes.

Personally, I don't think your aliases are that great because they have an unnecessary prefix. For example,

using PAIMenu = Pathfinding::Abstract::IMenu;

retains an unnecessary namespace abbreviation in the name, which also obscures the I interface marker in the name. Instead, I'd consider:

  • just aliasing the namespace

    namespace PA = Pathfinding::Abstract;
    
    ... PA::IMenu
    
  • putting the interface marker before the namespace abbreviation

    using IPAMenu = Pathfinding::Abstract::IMenu;
    
  • stripping the namespace away entirely (my preferred solution)

    using Pathfinding::Abstract::IMenu;
    

It might also be unnecessary to use such an alias in the first place. If the name is only used once or twice, it might be appropriate to just spell the fully-qualified name out every time. However, well-chosen abbreviations can also help to make complicated types more readable, especially in the context of templates or function signatures.

2
  • thanks for your reply, about your last point, "stripping the namespace away entirely (my preferred solution)", isn't that bad for the same reasons using namespace is bad(in headers), only on a smaller scale? I can't make that inside a class as far as I know. Also, using namespace PA = Pathfinding::Abstract; doesn't work ,for me, for some reason, maybe I am doing something wrong.
    – a a
    Mar 30, 2022 at 21:44
  • @aa I fixed the namespace alias example, it works without the using. There's a difference between using Qualified::Name and using namespace SomeNamespace – the first just brings Name into scope, the second brings all members of SomeNamespace into scope. This second variant is especially problematic in headers since you have no way to know what the namespace will contain at that time, potentially leading to name conflicts.
    – amon
    Mar 30, 2022 at 22:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.