4

Is it possible to detect whether at a given point of code you are in a namespace? In particular, I want to include a warning if a file is being including in the global namespace.

pythonic metaphor
  • 10,296
  • 18
  • 68
  • 110

3 Answers3

2

Good practice is including all headers in global namespace. Open all needed namespaces at the beginning of file and close them before end. Another way will inevitably lead to heap of problems.

** Comment extension **

To prevent unintended inclusion, you can do something like this:

In header:
#ifndef INTERNAL_INCLUDE
#error ...
#endif

When used:
#define INTERNAL_INCLUDE
#include "internal.h"
#undef INTERNAL_INCLUDE
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
Pavel Ognev
  • 962
  • 7
  • 15
  • 2
    Disagree. There are exceptions from this rule. For example in http://www.boost.org/doc/libs/1_51_0/boost/smart_ptr/shared_ptr.hpp there is following include `// implicit conversion to "bool" #include ` – ForEveR Sep 13 '12 at 16:04
  • In my case, I'm using a file to declare some typedefs that I wanted confined to a namespace, and then including this file inside some different namespaces. But, regardless of whether this is a good idea, it would be interesting to know the answer to my question. I'll mark my question language lawyer. – pythonic metaphor Sep 13 '12 at 16:14
  • I see, boost developers used this in similar way. So, if you want to prevent header file from being unwittingly included, I wish you to add a preprocessor condition: `#ifndef _SOME_VAR_ #error bad include #endif` – Pavel Ognev Sep 13 '12 at 16:22
2

I can give you a hint that generates compilation error if header is not include in global namespace. If I know C++ constructiom which for sure generates compiler warning (other that #warning) then it could be used instead of compilation error.

Put in your header:

template <class A, class B>
struct AreSame { enum { VALUE = -1 }; };
template <class A>
struct AreSame<A,A> { enum { VALUE = 1 }; };

struct TestGlobalNamespace
{
   int test_namespace[AreSame<TestGlobalNamespace, ::TestGlobalNamespace>::VALUE];
};

When your header is include in some namespace you'll get an error.

Like in this example:

namespace Some {

struct TestGlobalNamespace
{
   int test_namespace[AreSame<TestGlobalNamespace, ::TestGlobalNamespace>::VALUE];
};

}

You'll get:

prog.cpp:17: error: size of array ‘test_namespace’ is negative

[UPDATE]

However the more probably would be this kind of errors:

prog.cpp:17: error: ‘::TestGlobalNamespace’ has not been declared
prog.cpp:17: error: template argument 2 is invalid

Anyway - no one will dare to include your header to namespace other than global.

PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
1

You can do this with the small inconvenience of requiring a second header, to be included in the global namespace before the first.

// stuff_guard.h - include from global namespace to guard stuff.h
#ifndef STUFF_GUARD_H
#define STUFF_GUARD_H
typedef char stuff_guard[1];
#endif

// stuff.h - must be included from non-global namespace, after stuff_guard.h
// No include guard - may be included multiple times, in different namespaces.

#ifndef STUFF_GUARD_H
#error stuff_guard.h must be included before stuff.h
#endif

typedef char stuff_guard[2];

static_assert(sizeof (stuff_guard) != sizeof (::stuff_guard), 
    "stuff.h must not be included from the global namespace");

// Put your stuff here

This will give reasonably friendly error messages if you break either of these two rules, and a somewhat less friendly error if you include stuff_guard.h from a non-global namespace.

If you're stuck with an old compiler and static_assert isn't available, then you could use BOOST_STATIC_ASSERT, or roll your own.

Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644