Returning nested class within template class from member function.

J

jason.cipriani

I have some code like this that won't compile:

template <typename T> class MyClass {
public:
class Nested { };
Nested f ();
};

template <typename T> MyClass<T>::Nested f () { // <---problem
return Nested();
}

"Nested" is a non-template class, nested inside the template class
"MyClass". The MyClass member function f() returns a "Nested", and is
defined outside of the class declaration. I receive the following
error from Comeau (and similar errors from other compilers):

"ComeauTest.c", line 7: error: nontype "MyClass<T>::Nested [with T=T]"
is not a
type name
template <typename T> MyClass<T>::Nested f () {

What is the correct syntax to use here? I can't figure out how to make
this work (or if it's just not possible). Putting the definition of f
() right in the class declaration does work fine, but I'd like to keep
it outside, but mostly I'm curious about the syntax.

Thanks,
JC
 
J

jason.cipriani

I have some code like this that won't compile:

template <typename T> class MyClass {
public:
        class Nested { };
        Nested f ();

};

template <typename T> MyClass<T>::Nested f () { // <---problem
        return Nested();

}

"Nested" is a non-template class, nested inside the template class
"MyClass". The MyClass member function f() returns a "Nested", and is
defined outside of the class declaration. I receive the following
error from Comeau (and similar errors from other compilers):

"ComeauTest.c", line 7: error: nontype "MyClass<T>::Nested [with T=T]"
is not a
          type name
  template <typename T> MyClass<T>::Nested f () {

What is the correct syntax to use here? I can't figure out how to make
this work (or if it's just not possible). Putting the definition of f
() right in the class declaration does work fine, but I'd like to keep
it outside, but mostly I'm curious about the syntax.

Oops, I totally screwed that up! Forgot the "MyClass<T>::" before "f
()"... I got it figured out. This is correct:

template <typename T> MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}

All right, but now that I've fixed *my* stupid mistake, Comeau
compiles it fine, except MS's VC++ 2008 compiler choked on it:

1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1> prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'

But adding a "typename" in the middle there made it happy for some
reason:

template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}

Jason
 
O

olekk

I have some code like this that won't compile:

template <typename T> class MyClass {
public:
� � � � class Nested { };
� � � � Nested f ();

};

template <typename T> MyClass<T>::Nested f () { // <---problem
� � � � return Nested();

}

"Nested" is a non-template class, nested inside the template class
"MyClass". The MyClass member function f() returns a "Nested", and is
defined outside of the class declaration. I receive the following
error from Comeau (and similar errors from other compilers):

"ComeauTest.c", line 7: error: nontype "MyClass<T>::Nested [with T=T]"
is not a
� � � � � type name
� template <typename T> MyClass<T>::Nested f () {

What is the correct syntax to use here? I can't figure out how to make
this work (or if it's just not possible). Putting the definition of f
() right in the class declaration does work fine, but I'd like to keep
it outside, but mostly I'm curious about the syntax.

Oops, I totally screwed that up! Forgot the "MyClass<T>::" before "f
()"... I got it figured out. This is correct:

template <typename T> MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}

All right, but now that I've fixed *my* stupid mistake, Comeau
compiles it fine, except MS's VC++ 2008 compiler choked on it:

1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1> prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'

But adding a "typename" in the middle there made it happy for some
reason:

template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}

As compiler informs you - MyClass<T>::Nested is dependent name and
should be prefixed with typename keyword

template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}

Regards
 
T

Triple-DES

[...]
All right, but now that I've fixed *my* stupid mistake, Comeau
compiles it fine, except MS's VC++ 2008 compiler choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1>        prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy for some
reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
   return Nested();
}

  I'd say the 'typename' is necessary ('Nested' is a nested identifier
  depending on a template parameter, after all), but this seems to
  counter all my experience regarding whether Comeau or VC is right,
  whenever they disagree.
  Am I wrong here, or would this really be a bug in Comeau??

Yes, typename is required here (14.6/3), so it would be non-conformant
to compile this without a diagnostic.
 
J

James Kanze

[...]
All right, but now that I've fixed *my* stupid mistake,
Comeau compiles it fine, except MS's VC++ 2008 compiler
choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1> prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy
for some reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}
I'd say the 'typename' is necessary ('Nested' is a nested
identifier depending on a template parameter, after all),
but this seems to counter all my experience regarding
whether Comeau or VC is right, whenever they disagree.
Am I wrong here, or would this really be a bug in Comeau??

Check the options it was invoked with. Comeau is a very
professional product, which means that it doesn't go around
breaking existing code if it can help it. So it almost
certainly has modes which accept this code, and others which
don't.
 
J

jason.cipriani

James said:
(e-mail address removed) wrote:
[...]
All right, but now that I've fixed *my* stupid mistake,
Comeau compiles it fine, except MS's VC++ 2008 compiler
choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1>        prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy
for some reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
   return Nested();
}
  I'd say the 'typename' is necessary ('Nested' is a nested
  identifier depending on a template parameter, after all),
  but this seems to counter all my experience regarding
  whether Comeau or VC is right, whenever they disagree.
  Am I wrong here, or would this really be a bug in Comeau??
Check the options it was invoked with.  Comeau is a very
professional product, which means that it doesn't go around
breaking existing code if it can help it.  So it almost
certainly has modes which accept this code, and others which
don't.

  Good thought, however, it does accept this

    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };

    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }

  as

    Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
    Copyright 1988-2008 Comeau Computing.  All rights reserved.
    MODE:strict errors C++ noC++0x_extensions

  so it seems indeed this is a bug in Comeau.

Weird, I just immediately assumed that VS was the broken one. I did
not try with any other compiler besides VS and Comeau. I will report
the bug to Comeau and see what they say.

Jason
 
J

James Kanze

James said:
(e-mail address removed) wrote:
[...]
All right, but now that I've fixed *my* stupid mistake,
Comeau compiles it fine, except MS's VC++ 2008 compiler
choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1> prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy
for some reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
return Nested();
}
I'd say the 'typename' is necessary ('Nested' is a nested
identifier depending on a template parameter, after all),
but this seems to counter all my experience regarding
whether Comeau or VC is right, whenever they disagree.
Am I wrong here, or would this really be a bug in Comeau??
Check the options it was invoked with. Comeau is a very
professional product, which means that it doesn't go around
breaking existing code if it can help it. So it almost
certainly has modes which accept this code, and others which
don't.
Good thought, however, it does accept this
template <typename T> class MyClass {
public:
class Nested { };
Nested f ();
};
template <typename T> MyClass<T>::Nested MyClass<T>::f()
{
return Nested();
}

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions
so it seems indeed this is a bug in Comeau.

I don't think so. The typename here is optional, since Nested
is not a dependent name, but a locally declared name. If you
used MyClass<T>::Nested in the definition of another template,
the typename would be necessary, but not here. But IMHO, the
standard is far from clear about this. It goes into detail with
regards to when an expression is dependant, but it really
doesn't say much about names in declarations. About the only
really relevant text I can find is right at the start of §14.6,
where it says that "Three kinds of names can be used[...]", and
places names declared within the template itself in the same
category as the name of the template, i.e. locally declared. So
while Nested in MyClass<T>::Nested obviously depends on T, it
doesn't depend on T in the sense of the standard. (This makes
sense, of course, in that the compiler can easily determine that
Nested is a type; in the definition of template members, it
doesn't have to worry about specializations.)

FWIW: both g++ and Sun CC require the typename as well.
 
T

Triple-DES

Good thought, however, it does accept this
template <typename T> class MyClass {
public:
class Nested { };
Nested f ();
};
template <typename T> MyClass<T>::Nested MyClass<T>::f()
{
return Nested();
}
as
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions
so it seems indeed this is a bug in Comeau.

I don't think so. The typename here is optional, since Nested
is not a dependent name, but a locally declared name. If you
used MyClass<T>::Nested in the definition of another template,
the typename would be necessary, but not here. But IMHO, the
standard is far from clear about this. It goes into detail with
regards to when an expression is dependant, but it really
doesn't say much about names in declarations. About the only
really relevant text I can find is right at the start of §14.6,
where it says that "Three kinds of names can be used[...]", and
places names declared within the template itself in the same
category as the name of the template, i.e. locally declared. So
while Nested in MyClass<T>::Nested obviously depends on T, it
doesn't depend on T in the sense of the standard. (This makes
sense, of course, in that the compiler can easily determine that
Nested is a type; in the definition of template members, it
doesn't have to worry about specializations.)

Nevertheless, even locally declared names are considered dependent if
the name is qualified, per the current standard [14.6.2.1/1],
[14.6/6].

Consider:

template <typename T>
struct MyClass
{
class Nested { };
Nested f () const; // ok
MyClass<T>::Nested f(); // ill-formed, 'typename' required
};

Note that Comeau online seems to accept this in 'strict' mode, which
is not conforming to C++03.

But according to issue 224:
The decision on whether a name is dependent or non-dependent should be
based on lookup, not on the form of the name: if the name can be
looked up in the definition context and cannot be anything else as the
result of specialization, the name should be non-dependent.
 
V

Vidar Hasfjord

[...]
    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };
    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }
 [...]

I don't think so.  The typename here is optional, since Nested
is not a dependent name, but a locally declared name.  If you
used MyClass<T>::Nested in the definition of another template,
the typename would be necessary, but not here.

IOW, the member function template definition for f will only be
matched and instatiated for the MyClass base template, not any
(partial) specializations of MyClass, so the declaration of Nested is
fixed and typename should be implicit.
 But IMHO, the standard is far from clear about this.

Maybe the standard should give compilers some leeway on this. As far
as usage is concerned, requiring 'typename' here has little
consequence.

BTW, if I'm not mistaken the return part of the new C++0x style
function syntax is in the same scope as the function, and the above
can then be simplified to

template <typename T>
auto MyClass <T>::f () -> Nested {return Nested ();}

Regards,
Vidar Hasfjord
 
J

jason.cipriani

James said:
(e-mail address removed) wrote:
[...]
All right, but now that I've fixed *my* stupid mistake,
Comeau compiles it fine, except MS's VC++ 2008 compiler
choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1>        prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy
for some reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
   return Nested();
}
  I'd say the 'typename' is necessary ('Nested' is a nested
  identifier depending on a template parameter, after all),
  but this seems to counter all my experience regarding
  whether Comeau or VC is right, whenever they disagree.
  Am I wrong here, or would this really be a bug in Comeau??
Check the options it was invoked with.  Comeau is a very
professional product, which means that it doesn't go around
breaking existing code if it can help it.  So it almost
certainly has modes which accept this code, and others which
don't.
  Good thought, however, it does accept this
    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };
    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }
    Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
    Copyright 1988-2008 Comeau Computing.  All rights reserved.
    MODE:strict errors C++ noC++0x_extensions
  so it seems indeed this is a bug in Comeau.

Weird, I just immediately assumed that VS was the broken one. I did
not try with any other compiler besides VS and Comeau. I will report
the bug to Comeau and see what they say.

FWIW, GCC (3.4.5 mingw) also does not accept it without the
"typename", although the error message is less than informative:

$ g++ testme.cpp
testme.cpp:7: error: expected constructor, destructor, or type
conversion before
"MyClass"


Jason
 
J

jason.cipriani

James Kanze wrote:
(e-mail address removed) wrote:
[...]
All right, but now that I've fixed *my* stupid mistake,
Comeau compiles it fine, except MS's VC++ 2008 compiler
choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1>        prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy
for some reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
   return Nested();
}
  I'd say the 'typename' is necessary ('Nested' is a nested
  identifier depending on a template parameter, after all),
  but this seems to counter all my experience regarding
  whether Comeau or VC is right, whenever they disagree.
  Am I wrong here, or would this really be a bug in Comeau??
Check the options it was invoked with.  Comeau is a very
professional product, which means that it doesn't go around
breaking existing code if it can help it.  So it almost
certainly has modes which accept this code, and others which
don't.
  Good thought, however, it does accept this
    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };
    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }
  as
    Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
    Copyright 1988-2008 Comeau Computing.  All rights reserved.
    MODE:strict errors C++ noC++0x_extensions
  so it seems indeed this is a bug in Comeau.
Weird, I just immediately assumed that VS was the broken one. I did
not try with any other compiler besides VS and Comeau. I will report
the bug to Comeau and see what they say.

FWIW, GCC (3.4.5 mingw) also does not accept it without the
"typename", although the error message is less than informative:

$ g++ testme.cpp
testme.cpp:7: error: expected constructor, destructor, or type
conversion before
 "MyClass"

But dammit, Borland's compiler *does* accept it without complaining
(whatever version ships with RAD Studio 2007), bringing the whole
thing to a tie again.

Jason
 
J

James Kanze

  Good thought, however, it does accept this
    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };
    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }
  as
    Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
    Copyright 1988-2008 Comeau Computing.  All rights reserved.
    MODE:strict errors C++ noC++0x_extensions
  so it seems indeed this is a bug in Comeau.
I don't think so.  The typename here is optional, since
Nested is not a dependent name, but a locally declared name.
 If you used MyClass<T>::Nested in the definition of another
template, the typename would be necessary, but not here.
 But IMHO, the standard is far from clear about this.  It
goes into detail with regards to when an expression is
dependant, but it really doesn't say much about names in
declarations.  About the only really relevant text I can
find is right at the start of §14.6, where it says that
"Three kinds of names can be used[...]", and places names
declared within the template itself in the same category as
the name of the template, i.e. locally declared.  So while
Nested in MyClass<T>::Nested obviously depends on T, it
doesn't depend on T in the sense of the standard.  (This
makes sense, of course, in that the compiler can easily
determine that Nested is a type; in the definition of
template members, it doesn't have to worry about
specializations.)
Nevertheless, even locally declared names are considered
dependent if the name is qualified, per the current standard
[14.6.2.1/1], [14.6/6].

The standard is far from clear, but the first paragraph in §4.6
seems to say clearly that names are split up into three disjoint
sets. And MyClass<T>::Nested is a name declared within the
template itself, thus a locally declared name, and thus not
dependent. Other text makes it somewhat less clear, however,
and I can easily understand implementors interpreting the
standard differently in this regard. (In the end, it hinges on
the question of whether, in MyClass, MyClass<T> is a dependent
class. §16.6.2 can be read both ways, but §14.6.1 would seem to
clearly say no.)
Consider:
template <typename T>
struct MyClass
{
  class Nested { };
  Nested f () const; // ok
  MyClass<T>::Nested f(); // ill-formed, 'typename' required
};
Note that Comeau online seems to accept this in 'strict' mode,
which is not conforming to C++03.

I don't have a copy of C++03 handy here to verify, but it seems
legal according to C++98 and the latest draft (the two versions
I do have handy here).
But according to issue 224:
The decision on whether a name is dependent or non-dependent
should be based on lookup, not on the form of the name: if the
name can be looked up in the definition context and cannot be
anything else as the result of specialization, the name should
be non-dependent.

In other words, even the committee isn't certain.
 
J

James Kanze

[...]
    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };
    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }
 [...]
I don't think so.  The typename here is optional, since
Nested is not a dependent name, but a locally declared name.
 If you used MyClass<T>::Nested in the definition of another
template, the typename would be necessary, but not here.
IOW, the member function template definition for f will only
be matched and instatiated for the MyClass base template, not
any (partial) specializations of MyClass, so the declaration
of Nested is fixed and typename should be implicit.

If there is a specialization (partial or otherwise) of MyClass,
it must redeclare f (or there won't be an f in the
specialization); this definition does not define any such
redeclaration.
Maybe the standard should give compilers some leeway on this.
As far as usage is concerned, requiring 'typename' here has
little consequence.

I'm a little bit worried about another issue, however. What
happens if an expression with this type is used as an argument
to a function. Does dependent name lookup kick in for the
function name, or not? Could the fact that compilers apparently
treat it differently mean that you could write legal programs
which compiled to different semantics, depending on the
compiler?
 
T

Triple-DES

On Dec 3, 12:47 pm, Triple-DES <[email protected]> wrote:
The standard is far from clear, but the first paragraph in §4.6
seems to say clearly that names are split up into three disjoint
sets.  And MyClass<T>::Nested is a name declared within the
template itself, thus a locally declared name, and thus not
dependent.  Other text makes it somewhat less clear, however,
and I can easily understand implementors interpreting the
standard differently in this regard.  (In the end, it hinges on
the question of whether, in MyClass, MyClass<T> is a dependent
class.  §16.6.2 can be read both ways, but §14.6.1 would seem to
clearly say no.)

The relevant paragraph is 14.6/6:
(...)The keyword typename shall always be specified when the
member is referred to using a qualified name, even if the qualifier is
simply the class template name.

[Example:
template<class T> struct A {
typedef int B;
A::B b; // ill-formed: typename required before A::B
void f(A<T>::B); // ill-formed: typename required before A<T>::B
typename A::B g(); // OK
};
The keyword typename is required whether the qualified name is A or
A said:
I don't have a copy of C++03 handy here to verify, but it seems
legal according to C++98 and the latest draft (the two versions
I do have handy here).

This is essentialy the same example as the one in 14.6/6. Thus my
conclusion that MyClass<T>::Nested is always dependent, even inside
the definition of MyClass. But again, according to

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#224

it should be legal C++0x.
 
J

James Kanze

The relevant paragraph is 14.6/6:
(...)The keyword typename shall always be specified when the
member is referred to using a qualified name, even if the
qualifier is simply the class template name.

OK. In other words, it doesn't matter whether the name is
dependent or not.

This requrement doesn't really make sense to me, but then, most
of the rules concerning two phase lookup don't make sense to me.
[Example:
template<class T> struct A {
typedef int B;
A::B b; // ill-formed: typename required before A::B
void f(A<T>::B); // ill-formed: typename required before A<T>::B
typename A::B g(); // OK};

The keyword typename is required whether the qualified name is A or
A said:
I don't have a copy of C++03 handy here to verify, but it
seems legal according to C++98 and the latest draft (the two
versions I do have handy here).
This is essentialy the same example as the one in 14.6/6. Thus
my conclusion that MyClass<T>::Nested is always dependent,
even inside the definition of MyClass.

I don't think it's dependent, but according to the passage you
just quoted, however, it doesn't matter. Dependent or not, the
typename is required.
 
J

jason.cipriani

James said:
(e-mail address removed) wrote:
[...]
All right, but now that I've fixed *my* stupid mistake,
Comeau compiles it fine, except MS's VC++ 2008 compiler
choked on it:
1>warning C4346: 'MyClass<T>::Nested' : dependent name is not a type
1>        prefix with 'typename' to indicate a type
1>error C2143: syntax error : missing ';' before 'MyClass<T>::f'
But adding a "typename" in the middle there made it happy
for some reason:
template <typename T> typename MyClass<T>::Nested MyClass<T>::f () {
   return Nested();
}
  I'd say the 'typename' is necessary ('Nested' is a nested
  identifier depending on a template parameter, after all),
  but this seems to counter all my experience regarding
  whether Comeau or VC is right, whenever they disagree.
  Am I wrong here, or would this really be a bug in Comeau??
Check the options it was invoked with.  Comeau is a very
professional product, which means that it doesn't go around
breaking existing code if it can help it.  So it almost
certainly has modes which accept this code, and others which
don't.
  Good thought, however, it does accept this
    template <typename T> class MyClass {
    public:
      class Nested { };
      Nested f ();
    };
    template <typename T> MyClass<T>::Nested MyClass<T>::f()
    {
      return Nested();
    }
    Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
    Copyright 1988-2008 Comeau Computing.  All rights reserved.
    MODE:strict errors C++ noC++0x_extensions
  so it seems indeed this is a bug in Comeau.

Weird, I just immediately assumed that VS was the broken one. I did
not try with any other compiler besides VS and Comeau. I will report
the bug to Comeau and see what they say.

Well, I emailed them about it, and then bugged them again a week
later, but never got a response. Maybe it *is* a Comeau issue after
all... weird...

Jason
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top