 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Joe Pallas Guest
|
Posted: Wed Jul 16, 2003 2:05 am Post subject: Should class-member using declarations behave differently fr |
|
|
I cannot find anything in the standard that would account for this
peculiar difference in how using declarations behave when the name
being imported is an overload of both template and non-template
functions. I am getting the same result from both g++ and (the online
test version of) Comeau.
When I have an template function with non-template overload in a
namespace, the using declaration imports both the template and
non-template versions, so that the code below compiles successfully.
namespace NS {
template <typename T>
void f(const T &) { }
void f(const int &) { }
}
using NS::f;
int main() {
f(7); // use specific version
f(7.0); // use template version
return 0;
}
Now I try to do what seems to be the same thing, only with class
members declarations, and both g++ and Comeau complain:
class Base {
protected:
template <typename T>
void f(const T &) { }
void f(const int &) { }
};
class Derived : public Base {
public:
using Base::f; // make inherited f public
};
int main() {
Derived d;
d.f(7); // use specific version
d.f(7.0); // use template version
return 0;
}
Both compilers complain that Base::f(const T&) with T = double is
protected (Comeau says 'error: function "Base::f(const T &) [with
T=double]" is inaccessible' and g++ says "`void Base::f(const T&) [with
T = double]' is protected within this context").
I can't find anything in section 7.3.3 (or 11.3) that would explain why
the namespace using-declaration imports both the template and
non-template functions, but the class-member using-declaration does
not. In particular, I don't see anyway that the every-popular 7.3.3p5
statement "A using-declaration shall not name a template-id" could
explain this difference.
Are both compilers wrong (seems unlikely), or am I not reading the
standard correctly? If the latter, what is the text that explains the
difference?
Thanks.
joe
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Randy Maddox Guest
|
Posted: Wed Jul 16, 2003 4:47 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
[email]pallas (AT) cs (DOT) stanford.edu[/email] (Joe Pallas) wrote in message news:<EDA5B2A0-B6FF-11D7-9A62-000A959DF3B0 (AT) cs (DOT) stanford.edu>...
| Quote: | I cannot find anything in the standard that would account for this
peculiar difference in how using declarations behave when the name
being imported is an overload of both template and non-template
functions. I am getting the same result from both g++ and (the online
test version of) Comeau.
When I have an template function with non-template overload in a
namespace, the using declaration imports both the template and
non-template versions, so that the code below compiles successfully.
namespace NS {
template
void f(const T &) { }
void f(const int &) { }
}
using NS::f;
int main() {
f(7); // use specific version
f(7.0); // use template version
return 0;
}
Now I try to do what seems to be the same thing, only with class
members declarations, and both g++ and Comeau complain:
class Base {
protected:
|
Here's your problem. These names are protected.
| Quote: | template
void f(const T &) { }
void f(const int &) { }
};
class Derived : public Base {
public:
using Base::f; // make inherited f public
|
And your comment here clearly shows that you are trying to make a
protected name be public. That you cannot do.
| Quote: | };
int main() {
Derived d;
d.f(7); // use specific version
d.f(7.0); // use template version
return 0;
}
Both compilers complain that Base::f(const T&) with T = double is
protected (Comeau says 'error: function "Base::f(const T &) [with
T=double]" is inaccessible' and g++ says "`void Base::f(const T&) [with
T = double]' is protected within this context").
|
And the error messages are perfectly clear that the access specifier
is the problem.
| Quote: |
I can't find anything in section 7.3.3 (or 11.3) that would explain why
the namespace using-declaration imports both the template and
non-template functions, but the class-member using-declaration does
not. In particular, I don't see anyway that the every-popular 7.3.3p5
statement "A using-declaration shall not name a template-id" could
explain this difference.
Are both compilers wrong (seems unlikely), or am I not reading the
standard correctly? If the latter, what is the text that explains the
difference?
Thanks.
joe
|
I believe that if you just change protected to public in Base your
problem will go away.
Randy.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Christoph Schulz Guest
|
Posted: Wed Jul 16, 2003 5:06 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
Randy Maddox <rmaddox (AT) isicns (DOT) com> schrieb:
| Quote: | pallas (AT) cs (DOT) stanford.edu (Joe Pallas) wrote in message
news:<EDA5B2A0-B6FF-11D7-9A62-000A959DF3B0 (AT) cs (DOT) stanford.edu>...
class Base {
protected:
Here's your problem. These names are protected.
template
void f(const T &) { }
void f(const int &) { }
};
class Derived : public Base {
public:
using Base::f; // make inherited f public
And your comment here clearly shows that you are trying to make a
protected name be public. That you cannot do.
|
This is incorrect IMHO. 7.3.3/15 allows this:
class A {
//[...]
protected:
void g();
};
class B : public A {
//[...]
public:
using A::g; // B::g is a public synonym for A::g
};
Regards,
Christoph
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Wed Jul 16, 2003 9:28 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
In article <8c8b368d.0307160458.7889773 (AT) posting (DOT) google.com>, Randy
Maddox <rmaddox (AT) isicns (DOT) com> writes
| Quote: | And your comment here clearly shows that you are trying to make a
protected name be public. That you cannot do.
|
Of course you can, though I hate the way using declarations at class
scope work the fact is that the declarations are injected with the
access of the using declaration (and if any uses of the name are private
and the using declaration is other than private we have an error but
that is the only case.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Daveed Vandevoorde Guest
|
Posted: Thu Jul 17, 2003 2:02 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
[email]pallas (AT) cs (DOT) stanford.edu[/email] (Joe Pallas) wrote:
| Quote: | I cannot find anything in the standard that would account for this
peculiar difference in how using declarations behave when the name
being imported is an overload of both template and non-template
functions. I am getting the same result from both g++ and (the online
test version of) Comeau.
|
Strange, but I do think it's a bug in both compilers.
Daveed
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Sebastian Moleski Guest
|
Posted: Thu Jul 17, 2003 2:59 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
"Francis Glassborow" <francis (AT) robinton (DOT) demon.co.uk> wrote
| Quote: | In article <8c8b368d.0307160458.7889773 (AT) posting (DOT) google.com>, Randy
Maddox <rmaddox (AT) isicns (DOT) com> writes
And your comment here clearly shows that you are trying to make a
protected name be public. That you cannot do.
Of course you can, though I hate the way using declarations at class
scope work the fact is that the declarations are injected with the
access of the using declaration (and if any uses of the name are private
and the using declaration is other than private we have an error but
that is the only case.
|
I'm trying to parse your sentences (which are lacking any interpunctation except
for the one opening parenthesis). Are you saying that using declarations should
not change the access level of the names they inject?
sm
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Randy Maddox Guest
|
Posted: Fri Jul 18, 2003 2:37 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
[email]francis (AT) robinton (DOT) demon.co.uk[/email] (Francis Glassborow) wrote in message news:<NtkmfXBkQZF$Ew+v (AT) robinton (DOT) demon.co.uk>...
| Quote: | In article <8c8b368d.0307160458.7889773 (AT) posting (DOT) google.com>, Randy
Maddox <rmaddox (AT) isicns (DOT) com> writes
And your comment here clearly shows that you are trying to make a
protected name be public. That you cannot do.
Of course you can, though I hate the way using declarations at class
scope work the fact is that the declarations are injected with the
access of the using declaration (and if any uses of the name are private
and the using declaration is other than private we have an error but
that is the only case.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
|
I was so shocked by this response that I went back and checked the
Standard and you are absolutely correct, Francis. Although it seems
extremely counter-intutitive that a using declaration could make a
protected name public, that exact example is provided in 7.3.3/15. As
you note, the only restriction apparently is that we cannot make a
private name anything but private. IMHO this rather seems to violate
the whole concept of protected, but I do indeed stand corrected.
Randy.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
johnchx Guest
|
Posted: Fri Jul 18, 2003 6:11 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
[email]rmaddox (AT) isicns (DOT) com[/email] (Randy Maddox) wrote
| Quote: | And your comment here clearly shows that you are trying to make a
protected name be public. That you cannot do.
Of course you can, though I hate the way using declarations at class
scope work the fact is that the declarations are injected with the
access of the using declaration (and if any uses of the name are private
and the using declaration is other than private we have an error but
that is the only case.
|
[snip]
| Quote: | I was so shocked by this response that I went back and checked the
Standard and you are absolutely correct, Francis.
|
[snip]
| Quote: | IMHO this rather seems to violate
the whole concept of protected, but I do indeed stand corrected.
|
Actually, I'd say that it clarifies -- rather than violates -- the
concept of protected. A derived class is permitted to do anything it
wants with a protected member of a base class, including publishing it
to all the world.
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Fri Jul 18, 2003 10:34 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
In article <bf62sn$kel$1$830fa79d (AT) news (DOT) demon.co.uk>, Richard Smith
<richard (AT) ex-parrot (DOT) com> writes
| Quote: |
Francis Glassborow wrote:
Of course you can, though I hate the way using declarations at class
scope work the fact is that the declarations are injected with the
access of the using declaration (and if any uses of the name are private
and the using declaration is other than private we have an error but
that is the only case.
Apologies if I'm misunderstanding you, but are you saying that the following
is *not* an error?
class B {
private: int x;
};
class D : public B {
private: using B: ;
};
By my reading of 7.3.3/14,
|
No you are perfectly right however I am not convinced that it should be.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Roger Orr Guest
|
Posted: Sat Jul 19, 2003 1:37 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
"Randy Maddox" <rmaddox (AT) isicns (DOT) com> wrote
[snip]
| Quote: | Similar conceptually, but does this make sense? I hear what you're
saying with respect to protected, but it still bothers me that it
works that way. The designer of the base class chose protected access
for some reason, and at least part of that reason was that they didn't
feel public access was correct. This behavior allows that decision to
be undone in a derived class, and that's what bothers me. Undoing a
base class design decision in a derived class just doesn't feel right
to me. Clearly this is no different than if the derived class
provided a public forwarding member that called the base class
protected member, but that at least seems more explicit and is clearly
documented by the code itself.
|
I have no particular problem in principle with allowing a protected base
member being made public in a derived class.
<ASIDE>
At the risk of starting a flame war, which is not my intention, I think
protected is often abused by coders who can't decide whether the method
should be public or private.
</ASIDE>
The part that I don't like is that a using declaration applies the _same_
access to _all_ the methods with the given name, and so makes it possible to
inadvertently give access to a protected member with the same name as a
public member.
A contrived example:
class Base
{
protected:
void aMethod( int someValue );
public:
void aMethod();
};
class Derived : Base
{
public:
using Base::aMethod;
};
However I don't consider this is likely to be cause a real problem in most
code.
Roger Orr
--
MVP in C++ at 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Philippe Mori Guest
|
Posted: Sun Jul 20, 2003 12:51 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
| Quote: |
class Base {
protected:
template
void f(const T &) { }
void f(const int &) { }
};
class Derived : public Base {
public:
using Base::f; // make inherited f public
};
Both compilers complain that Base::f(const T&) with T = double is
protected (Comeau says 'error: function "Base::f(const T &) [with
T=double]" is inaccessible' and g++ says "`void Base::f(const T&) [with
T = double]' is protected within this context").
|
I was always thinking that it was working that way... That is that we
cannot give more access to a member in a derived class by an using
declaration.
I think that the only way to give more access is when we derive
privatly (or protectedly), from a class... In that case, we could restore
the access to the original level.
class B1 {
public :
void f();
};
class D1 : private B1 {
public:
using B1::f; // Restore f access to public...
};
IMHO, if there are many overload, each overload should have the
mimimum access between the original access and the access where
the using clause appears.
I think that your compilers are right... If I remember well, Borland
was also doing it that way.
Philipe
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Richard Smith Guest
|
Posted: Mon Jul 21, 2003 3:07 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
Francis Glassborow wrote:
| Quote: | No you are perfectly right however I am not convinced that it should be.
|
But it breaks encapsulation by allowing members of one class
access to the private members of another.
class B {
private: int x;
};
class D : public B {
void f() { cout << x << endl; }
};
This is an error: x is a private member of B so can't be
accessed by D. Now consider add a using declaration to D:
class D : public B {
private: using B: ;
void f() { cout << x << endl; }
};
Now the name x is a private member of D, which can be
accessed within D.
By allowing this you allow derived classes to access *any*
data member of a base class. I think this would be a very
bad idea indeed.
--
Richard Smith
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Mon Jul 21, 2003 6:33 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
In article <4fb4137d.0307202059.2be243d5 (AT) posting (DOT) google.com>, johnchx
<johnchx2 (AT) yahoo (DOT) com> writes
| Quote: | So, in at least one instance, this isn't undoing a design decision,
but simply following the design.
|
However the blunt way class scope using declarations work is unfortunate
to say the least. I have no problem with the ability of a derived class
to make a protected function public but I have a big problem with being
able to republish interfaces when I need to. Note that using
declarations should allow 'unhiding' of names and the designer of the
derived class does not need to know the extent to which the name is
overloaded, his class will track the base class design. This is not
currently the case, and I suspect we will now have to invent an
alternative syntax to overcome what we have done.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Richard Smith Guest
|
Posted: Tue Jul 22, 2003 6:47 pm Post subject: Re: Should class-member using declarations behave differentl |
|
|
Francis Glassborow wrote:
| Quote: | However we could have provided an alternative form in which the using
declaration still made the private member of the base class visible but
kept it unusable by D.
|
I'm not sure I fully understand what you mean by "visible
but ... unusable by D". In the following code, do you want
the using declaration to inject two aliases into D, one for
each overload in B, with one having public accesibility and
one having no accesibility?
class B {
private: void x(int);
public: void x();
};
class D : public B {
public: using B: ;
};
Imagine for a moment that there is an additional access-
specifier, "inaccessible", meaning inaccessible even from
within the class. This would make the above definition of D
equivalent to
class D : public B {
inaccessible: void x(int); // unimplemented
public: void x() { return B: (); }
};
So what if the user wants to add another overload of x to
the derived class:
class D : public B {
public:
using B: ;
void x(int);
};
This would then be an redefinition of x(int), and so the
presence (if not semnatics) of B: (int) suddenly become
part of the exposed interface of B. (They have to be
documented so users can avoid this type of problem.)
I'm not sure that allowing this extention is really
particularlly useful. It seems to me to just be moving the
problem.
| Quote: | What we have currently is that any name that is
overloaded with at least one private declaration cannot be handled via a
using declaration.
|
How common do you think this is? I can't say I've ever been
tempted to do this. Isn't it better to just say "don't do
it".
| Quote: | There is also the issue as to whether we should have had class scope
using declarations apply to data (they serve no useful purpose because
IIRC a name used for data cannot also be overloaded as a name for a
function.
|
They can be used to break the accessibility specified in the
base class, e.g.
class B {
protected: int x;
};
class D : public B {
public: using B: ;
};
Not a particularly good thing to be encouraging, but a use
none the less.
| Quote: | I think that we did not think carefully enough about the issues when we
introduced class scope using declarations.
|
Agreed. Another thing with class scope using declarations
that I've never properly understood is why there is an
ambiguity in the following code copied from 7.3.3/15:
struct A { int x(); };
struct B : A {};
struct C : A {
using A: ;
int x(int);
};
struct D : B, C {
using C: ;
int x(double);
};
int (D* d) {
return d->x(); // Ambiguous
}
--
Richard Smith
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Wed Jul 23, 2003 1:32 am Post subject: Re: Should class-member using declarations behave differentl |
|
|
In article <Pine.LNX.4.55.0307221422460.26164 (AT) sphinx (DOT) mythic-beasts.com>,
Richard Smith <richard (AT) ex-parrot (DOT) com> writes
| Quote: | Francis Glassborow wrote:
However we could have provided an alternative form in which the using
declaration still made the private member of the base class visible but
kept it unusable by D.
I'm not sure I fully understand what you mean by "visible
but ... unusable by D". In the following code, do you want
the using declaration to inject two aliases into D, one for
each overload in B, with one having public accesibility and
one having no accesibility?
class B {
private: void x(int);
public: void x();
};
class D : public B {
public: using B: ;
};
Imagine for a moment that there is an additional access-
specifier, "inaccessible", meaning inaccessible even from
within the class. This would make the above definition of D
equivalent to
class D : public B {
inaccessible: void x(int); // unimplemented
public: void x() { return B: (); }
};
|
Yes, exactly and overload resolution then precedes correctly and if
x(int) is selected a diagnostic is issued, exactly as would happen if
you had not declared any functions named x in the derived class. Note
that currently, if I need to override any function named x then I am in
trouble in the derived class because the overrider will hide the others
and the best I can do is to provide a private x(int) and not define it.
What makes it worse is that the private member functions stop being
implementation details, I have to know about them and any future
additions or removals of private members of the overload set.
| Quote: |
So what if the user wants to add another overload of x to
the derived class:
class D : public B {
public:
using B: ;
void x(int);
};
This would then be an redefinition of x(int), and so the
presence (if not semnatics) of B: (int) suddenly become
part of the exposed interface of B. (They have to be
documented so users can avoid this type of problem.)
|
Check how overriders currently work in the presence of a using
declaration. I think you will find that they are fine.
| Quote: |
I'm not sure that allowing this extention is really
particularlly useful. It seems to me to just be moving the
problem.
|
Unfortunately we cannot really allow this extension because the damage
is already done with the changed access rules for public and protected
members of an overload set.
| Quote: |
What we have currently is that any name that is
overloaded with at least one private declaration cannot be handled via a
using declaration.
How common do you think this is? I can't say I've ever been
tempted to do this. Isn't it better to just say "don't do
it".
|
It means that we just about cannot inject ctors into a derived class by
extending the using declaration rules and that is something many people
definitely do want to do.
| Quote: |
There is also the issue as to whether we should have had class scope
using declarations apply to data (they serve no useful purpose because
IIRC a name used for data cannot also be overloaded as a name for a
function.
They can be used to break the accessibility specified in the
base class, e.g.
class B {
protected: int x;
};
class D : public B {
public: using B: ;
};
Not a particularly good thing to be encouraging, but a use
none the less.
|
Now you are supporting poor coding as a justification. Note that under
what I wanted this breach of accessibility would not have been possible.
< snip>
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]
|
|
| Back to top |
|
 |
Powered by phpBB © 2001, 2006 phpBB Group
|