Topic: multiple using declarations in namespace scope


Author: Ewgenij Gawrilow <gawrilow@math.tu-berlin.de>
Date: Fri, 2 Feb 2001 23:45:46 GMT
Raw View
Let's imagine a class library defining two top-level classes. Each is
declared in a separate header file, as they can be used independently
from each other. Besides them, there is a lot of helper classes being of
little interest for library users. In such a situation
I'd prefer to introduce two distinct namespaces:

// file A.h
namespace implementation {
  class A { ... };
  // ...
  // a useful function
  void f(A);
};
namespace export_stuff {
  using implementation::A;
};

// file B.h
namespace  {
  class B { ... };
  // ...
  // a useful function again
  void f(B);
};
namespace export_stuff {
  using implementation::B;
};

The application program can then be written as follows:

#include <A.h>
#include <B.h>

using namespace export_stuff;
int main() {
   A a;
   B b;
   f(a); f(b);  // both will be found via Koenig's lookup
}

So far, so nice. My problem only begins here. Our useful function
suddenly turns out to be a function template with a template parameter
occuring in the return value and hence not deducible from the arguments:

// file A.h
namespace implementation {
  template <class X>
  X f(A);
};

and the same about B.

Now we can't rely on the Koenig's lookup in the application program any
more as the compiler complains about parse errors in the expression
f<int>(a). This could be cured, however, with

namespace export_stuff {
  using implementation::f;
};

The only question is: where to place this declaration? As I've already
said, A and B can be used separately, so it should be placed in both
header files. However, while the first declaration (in A.h) exports A::f
in the global namespace (conforming to [7.3.3] par.9), the second
declaration has simply no effect and leaves B::f invisible, although it
is already defined at this point.

I haven't found an explicit treatement of such a situation in the
Standard; I feel, however, that the using declarations, due to the
position-dependent effects, could be handled a bit differently from
typedefs or class forward declarations.

What's the experts' opinion?

PS: the workaround is easy - just full qualifying f in the application.
But it would go against the nice concept of the export namespace.
--
With best regards,
Ewgenij Gawrilow
Dept. of Mathematics
Technical University Berlin, Germany


Sent via Deja.com
http://www.deja.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Mon, 5 Feb 2001 11:05:13 GMT
Raw View
> Let's imagine a class library defining two top-level classes. Each is
> declared in a separate header file, as they can be used independently
> from each other. Besides them, there is a lot of helper classes being of
> little interest for library users. In such a situation
> I'd prefer to introduce two distinct namespaces:
>
> // file A.h
> namespace implementation {
>   class A { ... };
>   // ...
>   // a useful function
>   void f(A);
> };
> namespace export_stuff {
>   using implementation::A;
> };
>
> // file B.h
> namespace  {
>   class B { ... };
>   // ...
>   // a useful function again
>   void f(B);
> };
> namespace export_stuff {
>   using implementation::B;
> };
>
> The application program can then be written as follows:
>
> #include <A.h>
> #include <B.h>
>
> using namespace export_stuff;
> int main() {
>    A a;
>    B b;
>    f(a); f(b);  // both will be found via Koenig's lookup
> }
>
> So far, so nice. My problem only begins here. Our useful function
> suddenly turns out to be a function template with a template parameter
> occuring in the return value and hence not deducible from the arguments:
>
> // file A.h
> namespace implementation {
>   template <class X>
>   X f(A);
> };
>
> and the same about B.
>
> Now we can't rely on the Koenig's lookup in the application program any
> more as the compiler complains about parse errors in the expression
> f<int>(a).

This brings out a fairly interesting thing. According to the current version
of the Standard,  there is nothing that should stop  the argument-dependent
lookup from finding a function template. I.e. given the below code:

// file A.h
namespace implementation {
  class A { ... };
  // ...
  // a useful function
  template <class X>
  X f(A);
};
namespace export_stuff {
  using implementation::A;
};

// file main.cpp
#include <A.h>

using namespace export_stuff;
int main() {
   A a;
   f<int>(a);
   return  0;
}

an ANSI/ISO C++ compiler shall find (through the argument-dependent lookup)
that f is a function template, and treat < as the beginning of a
template-argument-list (See 14.2/3), without giving any parse errors for the
expression 'f<int>(a)'.

I tried compiling the code above using a few compilers, which all claim to
be ANSI/ISO C++  compliant to a lesser or greater extent,  and none of them
was able to compile the code.

The compilers I tried were:
MSVC 6.0, gcc 2.95.2, Borland C++ 5.5.1, and Comeau C/C++ 4.2.44 BETA#3.

> This could be cured, however, with
>
> namespace export_stuff {
>   using implementation::f;
> };
>
> The only question is: where to place this declaration? As I've already
> said, A and B can be used separately, so it should be placed in both
> header files. However, while the first declaration (in A.h) exports A::f
As far as I can see from the pieces you've given, nothing in A.h exports
f(A) into the global namespace. Did you mean the export_stuff namespace?

> in the global namespace (conforming to [7.3.3] par.9), the second
> declaration has simply no effect and leaves B::f invisible, although it
> is already defined at this point.
There's nothing in the Standard that provides for the ineffectiveness of
the second using-declaration. It's just that some compilers still fail to
recognize it. Of the above four compilers that I mentioned above, Comeau
C/C++ does the trick.

The second declaration in B.h
> namespace export_stuff {
>   using implementation::f;
> };
shall bring both declarations f(A) and f(B) into the export_stuff namespace
(provided that A.h is included first, of course). The declaration of 'f(A)'
shall have already been brought into export_stuff by the using-declaration
from A.h. As a result, f(A) is declared twice in export_stuff, but that's
all right, as the two declarations refer to the same entity.

Regards,

Andrei Iltchenko
Brainbench MVP for C++
http://www.brainbench.com




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]