#include within namespace scope

J

joecook

Is there anything that prevents putting #include directives inside
namespace scope within the standard?

Let's say I have a (evil) header:

header.h
#include <vector>
using namespace std; // bad doggy

class Doo
{
public:
vector<int> d;
};
----------
and a test.cc:
namespace evil
{
#include "header.h"
}
int main()
{
// Nothing
}

gcc throws up all over the place. What rule am I violating?

Joe C
 
P

Pascal J. Bourguignon

Is there anything that prevents putting #include directives inside
namespace scope within the standard?

Nothing, but you will declare the stuff defined in the header inside
this namespace.
Let's say I have a (evil) header:

Therefore you have:


namespace evil
{
#include <vector>
using namespace std; // bad doggy

class Doo
{
public:
vector<int> d;
};
}
int main()
{
// Nothing
}

That is, you are using a class evil::std::vector<int>
Where is the implementation of this class?
Notice that libg++ only defines methods such as std::vector<int>::clear,
not evil::std::vector<int>::clear.

So as long as you defined all the methods and classes you have defined
in evil::std somewhere, and would link them with your program it would
be ok.
 
Z

Zeppe

Is there anything that prevents putting #include directives inside
namespace scope within the standard?

I'd be surprised if it weren't.
Let's say I have a (evil) header:

header.h
#include <vector>
[...]

and a test.cc:
namespace evil
{
#include "header.h"
}
[...]

gcc throws up all over the place. What rule am I violating?

The rule of common sense. The headers include a bounch of declarations
and definitions within the namespace std, you cannot change the
namespace and expect that everything works.

A workaround is to #include <vector> in test.cc or elsewhere before the
inclusion in header.h, so that the standard things stay the same. Sort
of a new wrapper file:

header_wrap.h

#include <vector>
namespace evil{
#include <header.h> // vector won't be included in namespace evil.
}

Best wishes,

Zeppe
 
J

joecook

Nothing, but you will declare the stuff defined in the header inside
this namespace.


Therefore you have:

    namespace evil
    {
    #include <vector>
    using namespace std;  // bad doggy

    class Doo
    {
    public:
     vector<int> d;
    };
    }
    int main()
    {
      // Nothing
    }

That is, you are using a class  evil::std::vector<int>
Where is the implementation of this class?
Notice that libg++ only defines methods such as std::vector<int>::clear,
not evil::std::vector<int>::clear.

I expected the preprocessor to expand the include header at the
location I have put it.
I further expected that the compiler should always refer to ::std::
instead of std::, and therefore 'std' will not get caught inside the
namespace where it is not intended. Somewhere that expectation is
being broken, and I'm still not sure exactly where..
Joe C
 
J

joecook

I expected the preprocessor to expand the include header at the
location I have put it.
I further expected that the compiler should always refer to ::std::
instead of std::, and therefore 'std' will not get caught inside the
namespace where it is not intended.  Somewhere that expectation is
being broken, and I'm still not sure exactly where..
Joe C- Hide quoted text -

- Show quoted text -

To clarify,

The standard states, "Whenever a name x defined in the standard
library is mentioned, the name x is assumed to be fully qualified
as ::std::x, unless explicitly described otherwise. For example, if
the Effects section for library function F is described as calling
library function G, the function ::std::G is meant."

In this case, the compiler seems to be making the assumption that
include directives will always be at global scope, but I cannot find
any part of the standard that would back up such an assumption. That
is what I am searching for.

Thanks!
Joe C
 
P

Pascal J. Bourguignon

That's what it does.

They would have to write ::std:: all over the standard headers.
To clarify,

The standard states, "Whenever a name x defined in the standard
library is mentioned, the name x is assumed to be fully qualified
as ::std::x, unless explicitly described otherwise. For example, if
the Effects section for library function F is described as calling
library function G, the function ::std::G is meant."

This seems to me to be a meta-rule about the interpretation of the
text of the standard. It says nothing about the header files.

In this case, the compiler seems to be making the assumption that
include directives will always be at global scope, but I cannot find
any part of the standard that would back up such an assumption. That
is what I am searching for.

Or to infirm it. It would be nice to find it.
 
Z

Zeppe

Victor Bazarov wrote [16/02/09 15:01]:
The concept of a namespace has nothing to do with the preprocessor. So,
those two are orthogonal, and there can be NO provision making the two
somehow connected. Are you surprised?

In order for the std headers to work, they have to be included outside
of any namespace. Whatever the reason, this is a rule, and I expect it
to appear somewhere in the standard, since, as you said, namespaces and
preprocessor are orthogonal and in principle I could expect to be able
to include standard headers at any point.

But, no, I'm not surprised, because of 17.4.2.1#3:
"A translation unit shall include a header only outside of any external
declaration or definition, and shall include the header lexically before
the first reference to any of the entities it declares or first defines
in that translation unit."
Actually, more precisely, the namespace ::std.

yes, that is, of course. It was the whole core of the topic :)

Best wishes,

Zeppe
 
J

James Kanze

Is there anything that prevents putting #include directives
inside namespace scope within the standard?

Of course not. Include happens before namespaces are
recognized, and is pure textual inclusion. You can put one in
the middle of a function, if that's what you want.
The only restriction in the standard is with regards to the
standard includes; these must be included "outside of any
external declaration or definition." I'm not sure why the
particular exact wording, but namespaces and classes do count as
declarations, so the include of a standard header must be
outside of them.
Let's say I have a (evil) header:
header.h
#include <vector>
using namespace std; // bad doggy
class Doo
{
public:
vector<int> d;};
----------
and a test.cc:
namespace evil
{
#include "header.h"
}
int main()
{
// Nothing
}
gcc throws up all over the place. What rule am I violating?

You're including a standard header (indirectly) inside a
namespace.

More generally, since headers are textual inclusion, it's very
hard to write one which can really be included within a
namespace. The standard doesn't care, but there's a very large
possibility that the results will not be what you want (unless
the header only contains #define).
 
J

James Kanze

I expected the preprocessor to expand the include header at
the location I have put it. I further expected that the
compiler should always refer to ::std:: instead of std::, and
therefore 'std' will not get caught inside the namespace where
it is not intended.

Part of the problem may be that the library is doing just that:
using ::std::, instead of just std::. So <vector> includes
something like:

namespace std
{
namespace _Private_ {
class _UsedByVector { /* ... */ } ;
}
template< ... >
class vector
{
// ...
::std::_Private_::_UsedByVector ...
} ;
}

When you wrap this in namespace evil,
::std::_Private_::_UsedByVector isn't defined, only
::evil::std::_Private_::_UsedByVector.

It's because of such things that the standard makes the
requirement that standard headers may not be included in
declarations or definitions.
 
J

James Kanze

To clarify,
The standard states, "Whenever a name x defined in the standard
library is mentioned, the name x is assumed to be fully qualified
as ::std::x, unless explicitly described otherwise. For example, if
the Effects section for library function F is described as calling
library function G, the function ::std::G is meant."

I'm not sure where it says that, so I can't verify the context,
but I imagine that it is talking about the use of names in user
code. That the guarantees concerning e.g. vector only hold if
vector actually refers to ::std::vector (and not for
::evil::std::vector). And of course, you can't define a class:

template< ... >
class ::std::vector ...

(See §3.4.4/3, which specifies look-up after a class specifier
or an enum specifier. Particularly "If the name is a
qualified-id [the case in the above], [...]. If the name lookup
does not find a previously declared class-name or enum-name, the
elaborated-type-specifier is ill formed. In everyday terms:
class ::std::whatever ...
is ill formed unless there is a preceding
namespace std { class whatever; }
somewhere in global namespace.)
In this case, the compiler seems to be making the assumption
that include directives will always be at global scope, but I
cannot find any part of the standard that would back up such
an assumption.

The "compiler" is making no assumptions what so ever. It is
compiling what it sees, after textual inclusion. You're
violating §17.4.2.1/3 "A translation unit shall include a header
only outside of any external declaration, [...]"

More generally, most people assume that headers will be included
only outside of any external declaration when they write them.
This is almost always a constraint on the use of a header
(non-standard headers as well), and I suspect that it's often
not documented---unless the library documents that you can
include a header in a namespace, class definition or function
definition, I would assume that you couldn't.
 
J

James Kanze

That's what it does.
They would have to write ::std:: all over the standard
headers.

That doesn't help. You can't use a qualified name in an
"elaborated type specifier" (something beginning with the key
words "class", "struct", "union" or "enum") unless it has been
previously declared. Which means the the first mention of the
type cannot have the ::std::.
This seems to me to be a meta-rule about the interpretation of
the text of the standard. It says nothing about the header
files.

It would have been nice if he'd have provided the reference, so
we could see the context. I suspect what the above is saying is
that when the standard defines the behavior, etc. of vector, it
means ::std::vector. But it's hard to say without knowing the
context where the statement was made.
Or to infirm it. It would be nice to find it.

There are two separate issues.

There is absolutely no requirement that an include must be at
global scope. In the past, I've even used #include in a
function body. (I find this bad practice, and today, I do not
do it. Even if the include file is machine generated code,
designed to be included in one, and only one location, I will
ensure that the generated code will open and close any
namespaces, classes or functions that it needs, and will include
it at global scope.)

There is a requirement that the standard headers be included
outside any definition or declaration, i.e. outside of any
namespace, class, enum, function or template. See §17.4.2.1.
But this only applies to standard headers.

Finally, it's worth remembering that most library authors
probably make the same requirements, even if they don't say so.
I can't find anything in Posix saying that you can't include its
headers in the middle of a struct or function (since Posix is C,
there's no issue of namespaces), but I wouldn't expect it to
work. A priori, I would assume that any library have the same
restrictions as the standard library with regards to using its
headers, unless it explicitly documented them otherwise. In
other words, unless there is contrary documentation:

1. the headers may be included in any order;
2. they may be included more than once, with no differing
effect than if they were included only once,
3. they must be included outside any other definition or
declaration (at global scope, if you prefer, but also
outside of any declaration or definition which doesn't
introduce a new scope, e.g. enum); and
4. they must be included before the first use of anything they
define.

There will usually also be requirements concerning names that
may or may not be defined; something like:
#define std 3.14159
#include <vector>
is forbidden by the standard, and I expect just about every
library in existance has similar restrictions. (It might not
care about std, but it will have other symbols which will cause
problems.)
 
J

joecook

There is a requirement that the standard headers be included
outside any definition or declaration, i.e. outside of any
namespace, class, enum, function or template.  See §17.4.2.1.
But this only applies to standard headers.

Appreciate all the comments, and thanks for finding the reference I
was unable to find.
Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top