Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ Namespace headaches

Tags:

c++

namespaces

Okay, this question has evolved a bit, and I want to try to start (over) with the basic goals I'm shooting for:

  • Create library code that wrappers legacy C-language entities in C++ resource acquisition is initialization and also provides basic or better exception guarantee.
  • Enable clients of this code to use it in a very natural C++ fashion w/o creating a lot of overhead to existing code to convert it to use the C++ wrapper objects (i.e. automatic conversion to appropriate legacy types, constructors that take legacy types, etc.)
  • Limit the namespace impact of the library code. Ideally, The library would have several sub-namespaces that provide related functionality that limit the volume and impact of using namespace X type declarations - much as the boost libraries do (i.e. use of details namespaces to only inject those symbols that the user would reasonably want to use, and hide those that are implementation details; also limit the extent of possible new meanings to existing symbols, to avoid surprising implicit conversions within user-code)
  • Require that clients explicitly ask for those parts of the library that they actually want to inject into their code base. This goes hand in hand with limiting the impact of inclusion of the the library's headers. The client code should have a reasonable level of control over which parts of the library are going to be automatically used for name-resolution when they compile their code.
  • My own library code should not have to be riddled with refactor-brittle code constructs. It would be ideal if the library's headers didn't have to constantly declare private typedefs in order to have access to the rest of that section of the library. Or in other words: I want my library to be able to be written as intuitively as my clients get to when making use of said library. Name resolution should include the namespace that the library is defined within in addition to any others that have been explicitly "using'd".

I come across this scenario often, and am looking for a better way...

I have a class, C in namespace N. C has a member, Free. It free's something that C manages, and allows C to manage a new thing.

There are several global Free functions. There are also a few helper functions in the same namespace N as C, one of which is a helper that free's the thing managed by C, named free.

So we have something like:

namespace N {

void free(THING * thing);

class C
{
public:
  ... details omitted...
  free()
  { 
    free(m_thing); // <- how best to refer to N::free(THING&)
  }
}

} // namespace N

I could use N::free(m_thing). But that seems unfortunate to me. Is there no way to refer to that which is outside the class scope but without resolving absolute namespace (a relative one step out scope-wise)?

It seems to me that having to name N::free is obnoxious, since you wouldn't have to if this were a free-standing function. Nor would you need to if the class's method name happened to be different (e.g. dispose). But because I've used the same name, I cannot access it without having to specify what amounts to an absolute path - rather than a relative path - if you'll indulge me the analogy.

I hate absolute paths. They make moving things around in namespaces very brittle, so code-refactoring becomes much uglier. Plus, the rules of how to name things in function bodies becomes more complex with the current set of rules (as I understand them) - less regular - inducing a schism between what one expects and what one gets as a programmer.

Is there a better way to access free-standing functions in the same namespace as a class without having to absolutely name the free-function absolutely?

EDIT: Perhaps I should have gone with a less abstract example:

namespace Toolbox {
  namespace Windows {

// deallocates the given PIDL
void Free(ITEMIDLIST ** ppidl);

class Pidl
{
public:
    // create empty
    Pidl() : m_pidl(NULL) { }

    // create a copy of a given PIDL
    explicit Pidl(const ITEMIDLIST * pidl);

    // create a PIDL from an IShellFolder
    explicit Pidl(IShellFolder * folder);

    ...

    // dispose of the underlying ITEMIDLIST* so we can be free to manage another...
    void Free();
};

So ITEMIDLIST* come from a variety of places, and are destroyed with CoTaskMemFree(). I could introduce Pidl as a global name - as well as all of the helper functions in the "Windows Shell.h" header that is part of my toolbox library.

Ideally, I would segment some of the tools in my library by what they relate to - in this case the above all relates to COM programming in Windows. I have chose Toolbox as the base namespace for my libraries stuff, and was currently thinking I'd use Toolbox::Windows for very windows-y functions, classes, etc.

But the C++ namespace and name-resolution rules seem to make this very difficult (hence this question). It makes it very unnatural to create such segmentation of my code - since koenig lookup fails (since ITEMIDLIST is not in my Toolbox::Windows namespace), and I don't have the ability to move it there! Nor should I. The language should be flexible enough, IMO, to both allow for extension libraries such as my Toolbox library to extend other folks code without having to inject my extensions into their namespace (which, in the case of Win32 and the general vast majority of code that exists today, is the GLOBAL NS - which is the whole point of making namespaces in the first place: to avoid global NS crowding / pollution / ambiguity / programming surprises).

So, I come back around to, Is there a better way to do this: Extend existing libraries of code while not polluting their NS with my extensions but still allow for intuitive and useful name resolution as one would expect if my code were in their NS but explicitly introduced by the client of my code (i.e. I don't want to inject my code willy-nilly, but only upon explicit request)?

Another Thought: Perhaps what would satisfy my above criterea would be if I had the following:

using namespace X {
  code here...
}

Where I could place such a construct anywhere, including in a header, and I would not have to be concerned about dragging X into my client's code, but I would have the same freedom to write my source code as I would if I were in the root namespace.

like image 890
Mordachai Avatar asked Dec 14 '09 18:12

Mordachai


People also ask

What is C namespace?

Namespace is a feature added in C++ and is not present in C. A namespace is a declarative region that provides a scope to the identifiers (names of functions, variables or other user-defined data types) inside it. Multiple namespace blocks with the same name are allowed.

What does using namespace std mean?

“using namespace std” means we use the namespace named std. “std” is an abbreviation for standard. So that means we use all the things with in “std” namespace. If we don't want to use this line of code, we can use the things in this namespace like this.

Should we use using namespace std in C++?

The statement using namespace std is generally considered bad practice. The alternative to this statement is to specify the namespace to which the identifier belongs using the scope operator(::) each time we declare a type.


2 Answers

I don't see to avoid having to qualify namespace-scope free() here, but it should be noted that this is not the same as an "absolute path". For one thing, if you have nested namespaces, you only have to refer to the innermost one:

namespace N1 {
  namespace N2 {
    namespace N3 {
      void free(THING * thing);

      class C {
      public:
        free() {
          N3::free(m_Thing); // no need to do N1::N2::
        }
      };
    }
  }
}

[EDIT] in response to edited question. Again, I do not see any way to do this in the exact scenario that you describe. However, it doesn't seem to be idiomatic C++ approach - the more common way to do the same is to provide your own wrapper class for ITEMIDLIST that manages all allocations, RAII-style, and exposes the original handle (e.g. via conversion operators a la ATL, or an explicit member function like c_str() if you want extra safety). That would remove the need for your free altogether, and for any other free function that you might want there, since you control the wrapper type and the namespace it's in, you can use ADL as usual.

[EDIT #2]. This part of the question:

allow for intuitive and useful name resolution as one would expect if my code were in their NS but explicitly introduced by the client of my code (i.e. I don't want to inject my code willy-nilly, but only upon explicit request)?

Isn't this precisely what you putting it in a namespace, and your client writing using namespace ..., will achieve?

like image 95
Pavel Minaev Avatar answered Sep 30 '22 01:09

Pavel Minaev


You have two options:

  1. Fully qualify function name.
  2. Let Koenig lookup do the job (if THING belongs to namespace N).

I'd choose the first one with such popular function name as free.

Alternate option is to use m_thing->Release() or something like that.

like image 37
Kirill V. Lyadvinsky Avatar answered Sep 30 '22 01:09

Kirill V. Lyadvinsky