Topic: Namespace template parameters


Author: Christopher Eltschka <celtschk@web.de>
Date: Tue, 9 Oct 2001 17:22:29 GMT
Raw View
"Paul Mensonides" <leavings@home.com> writes:

> "Christopher Eltschka" <celtschk@web.de> wrote in message
> news:9pk9rr$baj$1@news.tuwien.ac.at...
> [snip]
> > Indeed, all the traits classes are really emulating templated
> > namespaces. Traits classes have no internal state or behaviour,
> > they just collect information related to a type.
> >
> > However, the fact that namespaces are extendable causes additional
> > things to be considered.
> >
> > template<class T> namespace N
> > {
> >   void foo(T);
> > }
> >
> > template<> namepace N<int> // (*)
> > {
> >   void bar(T);
> > }
> >
> > Now, does the line (*) add to namespace N<int>, or does it replace
> > namespace N<int> (as it would do with classes)? That is, does N<int>
> > now contain both void foo(T) and void bar(T), or does it contain only
> > void bar(T)?
> >
> > I think both behaviours are useful; therefore there should be a way to
> > distinguish between them.
>
> I think that it should replace it--for consistency.  After all, you would be
> able to emulate the extension behavior anyway (in a more logical fashion
> then "inheritance" from the default template):
>
> template<class T> namespace Shared {
>     void foo(T);
> }
>
> template<class T> void Shared<T>::foo(T t) { ... }
>
> template<class T> namespace N {
>     using namespace Shared<T>;
>
>     // ... general<T> functions ...
> }
>
> template<> namespace N<int> {
>     using namespace Shared<int>;
>
>     void bar(int);
>     // .. specific<int> functions ...
> }
>
> void N<int>::bar(int t) { ... }

However, what if I _then_ add to the general template?

template<class T> namespace N
{
  int i;
}

template<> namespace N<int>
{
  int j;
}

template<class T> namespace N
{
  int k;
}

Should now N<int> contain k or not? (Note that the first definitions
could be buried somewhere in headers => possible surprise
factor). It's obvious that N<double> should contain it.

Also, given the following definitions:

template<class T> namespace N
{
  int i;
}

template<class T> namespace N<std::pair<T, int> >
{
  int j;
}

template<class T> namespace N<std::pair<int, T> >
{
  int k;
}

Now what is in the namespace N<std:pair<int, int> >? (Or is that an
illegal namespace due to ambiguity?)

And what about the following code:

template<class T> namespace N
{
  int i = 5;
}

using namespace N<int>;

template<> namespace N<int>
{
}

int j = i; // legal?

---
[ 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                ]





Author: "Paul Mensonides" <leavings@home.com>
Date: Tue, 9 Oct 2001 23:56:15 GMT
Raw View
"Christopher Eltschka" <celtschk@web.de> wrote in message
news:9pvacj$s3f$1@news.tuwien.ac.at...
> However, what if I _then_ add to the general template?
>
> template<class T> namespace N
> {
>   int i;
> }
>
> template<> namespace N<int>
> {
>   int j;
> }
>
> template<class T> namespace N
> {
>   int k;
> }
>
> Should now N<int> contain k or not? (Note that the first definitions
> could be buried somewhere in headers => possible surprise
> factor). It's obvious that N<double> should contain it.

No, like I said before, this would be irregular, and more of a problem than
a help (especially with overload resolution, etc.).  If you want data shared
by specializations of a *theoretical* template namespace and various
explicit or partial specializations you should have to bring it into the
scope from somewhere else (like another namespace).  The same is true for
template class specializations.  If you want them to share stuff, you can
inherit from a non-templated base class.  Namespaces could be similar,
except with using directives and declarations.  Though I'm not sure what
Koenig lookup does in the following case:

namespace N1 {
    struct X;
}

namespace N2 {
    X f(X, X); // <--------
}

namespace N1 {
    using namespace N2;
}

int main() {
    N1::X a, b;
    f(a, b); // <--- does Koenig lookup find this function ?
    return 0;
}

//--> I tested this out on Comeau.
If you put "using namespace N2;" it doesn't find it, but if you put "using
N1::f;" it does.

> Also, given the following definitions:
>
> template<class T> namespace N
> {
>   int i;
> }
>
> template<class T> namespace N<std::pair<T, int> >
> {
>   int j;
> }
>
> template<class T> namespace N<std::pair<int, T> >
> {
>   int k;
> }
>
> Now what is in the namespace N<std:pair<int, int> >? (Or is that an
> illegal namespace due to ambiguity?)

It would obviously be ambiguous in the case of T = int.  Which, of course,
you could explicitly specialize away:

template<> namespace N<std::pair<int, int> > {
    int j, k;
}

> And what about the following code:
>
> template<class T> namespace N
> {
>   int i = 5;
> }
>
> using namespace N<int>;
>
> template<> namespace N<int>
> {
> }
>
> int j = i; // legal?

Isn't it already illegal to use template specializations like this?  If not,
it should be handled similarly to the current rules for classes and
functions.  This is somewhat pathological anyway.  You could disallow the
explicit (or partial) specialization of a template namespace that has
already been used.  Or you could look in the included scopes at the point of
use, like the second appearance of i above.  In which case, it would be
illegal since no i is in the global or N<int> scopes.

I tested a similar thing with classes with Comeau...

- - - - -

#include <iostream>

template<class T> struct N {
    static int i;
};

template<class T> int N<T>::i = 5;

int j = N<int>::i;

template<> struct N<int> { };

int main() {
    std::cout << j << std::endl;
    return 0;
}

- - - - -

Which produces:

error:  explicit specialization of class "N<int>" must precede its first use
template<> struct N<int> { };
                  ^

I think the namespace issue above should be handled analogously.

Therefore the line "using namespace N<int>;" would constitute "first use."

Paul Mensonides

---
[ 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                ]





Author: "James Russell Kuyper Jr." <kuyper@wizard.net>
Date: Thu, 4 Oct 2001 19:26:10 GMT
Raw View
I've purchase D&E, and in it I find that Stroustrup spoke favorably of
extending template parameters to include namespace names. It sounds
technically simple to implement, the syntax that should be used is
obvious, it looks somewhat useful, and it had the support of the
original author of the language. Whatever happened to this idea?

---
[ 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                ]





Author: "Paul Mensonides" <leavings@home.com>
Date: Fri, 5 Oct 2001 02:10:38 GMT
Raw View
"James Russell Kuyper Jr." <kuyper@wizard.net> wrote in message
news:3BBC4B11.DF02967F@wizard.net...
> I've purchase D&E, and in it I find that Stroustrup spoke favorably of
> extending template parameters to include namespace names. It sounds
> technically simple to implement, the syntax that should be used is
> obvious, it looks somewhat useful, and it had the support of the
> original author of the language. Whatever happened to this idea?

You can already fake it to good effect with static members and types, which
is why the language should directly support it, since it would be natural
(and relatively trivial to implement--especially given Koenig lookup).

namespace X {
    struct NS { };
    int f(int x, int y, int z, /* dummy arg */ NS) {
        return x + y + z;
}

namespace Y {
    struct NS { };
    int f(int x, int y, int z, NS) {
        return x - y - z;
    }
}

template<class T> struct Z {
    int select(void) {
        return f(10, 5, 2, T()); // Koenig lookup (i.e. namespace selection)
    }
};

It would be nice to have template namespaces as well.  You can already kind
of do it with an enclosing class scope, but classes are closed while
namespaces are open.  If you could do that, you could eliminate a great deal
of boilerplate template declarations.

template<class CharacterType> namespace Lexer {
    typedef CharacterType Ch;
    struct Token;

    // various lexer-type functions
    void f(void) { ... }
    void g(void) { ... }
    void h(void) { ... }
    void i(void) { ... }
        // etc.
}

-- rather than --

namespace Lexer {
    template<class Ch> struct Token;

    // various lexer-type functions
    template<class Ch> void f(void) { ... }
    template<class Ch> void g(void) { ... }
    template<class Ch> void h(void) { ... }
    template<class Ch> void i(void) { ... }
        // etc.
}

It would also be nice to allow class definitions outside their "name"
declaration in namespaces (just like inner classes).

namespace X {
    struct Y;
}

struct X::Y {
    // ...
};

That aside, I do agree that namespace parameters would be useful, and a
great way to switch a great deal of functionality with one template
parameter rather than many.

Paul Mensonides

---
[ 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                ]





Author: "Pavel Kuznetsov" <9y44-iu9t@spamex.com>
Date: Fri, 5 Oct 2001 16:00:30 GMT
Raw View
Paul Mensonides <leavings@home.com> wrote:
> It would be nice to have template namespaces as well.

Should template namespaces participate in Koenig lookup?

--
Pavel Kuznetsov

[ THE REPLY ADDRESS IS NOT GUARANTEED TO LIVE LONGER THAN FEW WEEKS! ]
[ The permanent address is: pavel <dot> kuznetsov <at> mail <dot> ru ]


---
[ 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                ]





Author: Christopher Eltschka <celtschk@web.de>
Date: Fri, 5 Oct 2001 17:47:51 GMT
Raw View
"Paul Mensonides" <leavings@home.com> writes:

> "James Russell Kuyper Jr." <kuyper@wizard.net> wrote in message
> news:3BBC4B11.DF02967F@wizard.net...
> > I've purchase D&E, and in it I find that Stroustrup spoke favorably of
> > extending template parameters to include namespace names. It sounds
> > technically simple to implement, the syntax that should be used is
> > obvious, it looks somewhat useful, and it had the support of the
> > original author of the language. Whatever happened to this idea?
>
> You can already fake it to good effect with static members and types, which
> is why the language should directly support it, since it would be natural
> (and relatively trivial to implement--especially given Koenig lookup).
>
> namespace X {
>     struct NS { };
>     int f(int x, int y, int z, /* dummy arg */ NS) {
>         return x + y + z;
> }
>
> namespace Y {
>     struct NS { };
>     int f(int x, int y, int z, NS) {
>         return x - y - z;
>     }
> }
>
> template<class T> struct Z {
>     int select(void) {
>         return f(10, 5, 2, T()); // Koenig lookup (i.e. namespace selection)
>     }
> };
>
> It would be nice to have template namespaces as well.  You can already kind
> of do it with an enclosing class scope, but classes are closed while
> namespaces are open.

Indeed, all the traits classes are really emulating templated
namespaces. Traits classes have no internal state or behaviour,
they just collect information related to a type.

However, the fact that namespaces are extendable causes additional
things to be considered.

template<class T> namespace N
{
  void foo(T);
}

template<> namepace N<int> // (*)
{
  void bar(T);
}

Now, does the line (*) add to namespace N<int>, or does it replace
namespace N<int> (as it would do with classes)? That is, does N<int>
now contain both void foo(T) and void bar(T), or does it contain only
void bar(T)?

I think both behaviours are useful; therefore there should be a way to
distinguish between them.

[...]

---
[ 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                ]





Author: "Paul Mensonides" <leavings@home.com>
Date: Sun, 7 Oct 2001 16:41:48 CST
Raw View
"Christopher Eltschka" <celtschk@web.de> wrote in message
news:9pk9rr$baj$1@news.tuwien.ac.at...
[snip]
> Indeed, all the traits classes are really emulating templated
> namespaces. Traits classes have no internal state or behaviour,
> they just collect information related to a type.
>
> However, the fact that namespaces are extendable causes additional
> things to be considered.
>
> template<class T> namespace N
> {
>   void foo(T);
> }
>
> template<> namepace N<int> // (*)
> {
>   void bar(T);
> }
>
> Now, does the line (*) add to namespace N<int>, or does it replace
> namespace N<int> (as it would do with classes)? That is, does N<int>
> now contain both void foo(T) and void bar(T), or does it contain only
> void bar(T)?
>
> I think both behaviours are useful; therefore there should be a way to
> distinguish between them.

I think that it should replace it--for consistency.  After all, you would be
able to emulate the extension behavior anyway (in a more logical fashion
then "inheritance" from the default template):

template<class T> namespace Shared {
    void foo(T);
}

template<class T> void Shared<T>::foo(T t) { ... }

template<class T> namespace N {
    using namespace Shared<T>;

    // ... general<T> functions ...
}

template<> namespace N<int> {
    using namespace Shared<int>;

    void bar(int);
    // .. specific<int> functions ...
}

void N<int>::bar(int t) { ... }

Paul Mensonides

---
[ 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                ]





Author: "Paul Mensonides" <leavings@home.com>
Date: Sun, 7 Oct 2001 16:44:26 CST
Raw View
"Pavel Kuznetsov" <9y44-iu9t@spamex.com> wrote in message
news:9pk88j$irt6d$1@ID-97366.news.dfncis.de...
> Paul Mensonides <leavings@home.com> wrote:
> > It would be nice to have template namespaces as well.
>
> Should template namespaces participate in Koenig lookup?

Why not?  The type of the object is still a parametized template.
NS<int>::X rather than NS::X<int>.  Given a template namespace X, and class
Y, and a function f:

template<class T> namespace X {
    class Y { ... };
    void f(Y y);
}

// and a explicit (or partial specialization):

template<> namespace X<int> {
    class Y { ... };
}

int main() {
    X<double>::Y a;
    X<int>::Y b;
    f(a); // found f in namespace X<double>
    f(b); // error:  no f in namespace X<int> (where b came from)

    return 0;
}

Paul Mensonides

---
[ 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                ]