User defined conversion to builtin type gives l-value?

Discussion in 'C++' started by Arne Mertz, Apr 11, 2009.

  1. Arne Mertz

    Arne Mertz Guest

    Hi all, following example:

    template <class T, class U>
    T foo(U const& u, T const& t)
    {
    return T temp(u) /= t;
    }

    gives me an error "'/=' left operand has to be an l-value" on MSVC
    2008 express, if T is a builtin type (e.g. double). In my case, U
    has an konversion operator to double. If I try the same with T being
    a builtin class and either providing a konversion ctor for T or
    providing an konversion operator for U, it works.
    My question is: is that right according to the standard? I found a
    line saying that implicit standard conversions result in l-values,
    but as far as i can see this is an explicitly called user defined
    conversion or not?

    greets
    A
     
    Arne Mertz, Apr 11, 2009
    #1
    1. Advertising

  2. * Arne Mertz:
    > Hi all, following example:
    >
    > template <class T, class U>
    > T foo(U const& u, T const& t)
    > {
    > return T temp(u) /= t;


    This is syntactically incorrect.

    Perhaps you meant

    return T(u)/t;


    > }
    >
    > gives me an error "'/=' left operand has to be an l-value" on MSVC 2008
    > express, if T is a builtin type (e.g. double). In my case, U has an
    > konversion operator to double. If I try the same with T being a builtin
    > class


    There are only a few classes that have direct compiler support, they include
    typeinfo and some exception classes.

    And it's still arguable whether they could be referred to as builtin classes.

    Probably you meant "builtin type".


    > and either providing a konversion ctor for T or providing an
    > konversion operator for U, it works.


    You cannot provide a constructor for a built-in type.


    > My question is: is that right according to the standard?


    Your code should not compile, if that's what you're asking.


    > I found a line
    > saying that implicit standard conversions result in l-values, but as far
    > as i can see this is an explicitly called user defined conversion or not?


    Huh?


    Cheers & hth.,

    - Alf


    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
     
    Alf P. Steinbach, Apr 11, 2009
    #2
    1. Advertising

  3. Arne Mertz

    Arne Mertz Guest

    Alf P. Steinbach schrieb:
    > * Arne Mertz:
    >> Hi all, following example:
    >>
    >> template <class T, class U>
    >> T foo(U const& u, T const& t)
    >> {
    >> return T temp(u) /= t;

    >
    > This is syntactically incorrect.
    >
    > Perhaps you meant
    >
    > return T(u)/t;


    Yes, sorry.
    >
    >
    >> }
    >>
    >> gives me an error "'/=' left operand has to be an l-value" on MSVC
    >> 2008 express, if T is a builtin type (e.g. double). In my case, U has
    >> an konversion operator to double. If I try the same with T being a
    >> builtin class

    >
    > There are only a few classes that have direct compiler support, they
    > include typeinfo and some exception classes.
    >
    > And it's still arguable whether they could be referred to as builtin
    > classes.
    >
    > Probably you meant "builtin type".


    Nope, sorry, I meant user defined class.
    >
    >
    >> and either providing a konversion ctor for T or providing an
    >> konversion operator for U, it works.


    >> My question is: is that right according to the standard?

    >
    > Your code should not compile, if that's what you're asking.
    >
    >
    >> I found a line saying that implicit standard conversions result in
    >> l-values, but as far as i can see this is an explicitly called user
    >> defined conversion or not?

    >
    > Huh?
    >


    Okay, seems I messed it all up a bit. So another try here:


    template <class T, class U>
    T foo(U const& u, T const& t)
    {
    return T(u) /= t;
    }

    class X {};

    struct Y
    {
    Y() {};
    Y(X const&) {}; //konversion ctor userdefined->userdefined (1)
    Y(int); //konversion ctor builtin->userdefined (2)
    Y& operator /= (Y const& rhs) {}
    };

    struct Z
    {
    operator Y() const; //konversion op userdefined->userdefined (3)
    operator double() const; //konversion op userdefined->builtin (4)
    };

    int main()
    {
    X x; Y y; Z z; int i; double d;

    foo(x, y); // calls (1), ok.
    foo(i, y); // calls (2), ok.

    foo(z, y); // calls (3), ok.
    foo(z, i); // calls (4), ERROR, because int(z) is l-value

    foo(i, d); // calls double(i) /= d; ERROR because double(i) is
    l-value
    }

    as far as I can the conversion in foo is explicit. I could not find
    any phrase in the standard saying whether the result of an explicit
    conversion is an l-value or an r-value. as it seems, either the
    conversion to userdefined types gives l-values, or the userdefined
    op/= can be applied to r-values in contrast to the builtin op/=
    Which is the case?

    greets
    A
     
    Arne Mertz, Apr 11, 2009
    #3
  4. * Arne Mertz:
    >
    > I could not find any
    > phrase in the standard saying whether the result of an explicit
    > conversion is an l-value or an r-value.


    It's an rvalue.


    > as it seems, either the
    > conversion to userdefined types gives l-values, or the userdefined op/=
    > can be applied to r-values in contrast to the builtin op/=


    Yes.

    Any accessible non-static member function can be applied to a non-const rvalue
    of class type.

    Note: that includes a compiler-generated operator=.


    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
     
    Alf P. Steinbach, Apr 11, 2009
    #4
  5. * Alf P. Steinbach:
    > * Arne Mertz:
    >>
    >> I could not find any phrase in the standard saying whether the result
    >> of an explicit conversion is an l-value or an r-value.

    >
    > It's an rvalue.


    More precisely (I didn't register that phrasing) the expression is an rvalue.

    The result at run time when the expression is evaluated is an object.

    Objects are neither lvalues nor rvalues, only expressions are.


    >> as it seems, either the conversion to userdefined types gives
    >> l-values, or the userdefined op/= can be applied to r-values in
    >> contrast to the builtin op/=

    >
    > Yes.
    >
    > Any accessible non-static member function can be applied to a non-const
    > rvalue of class type.
    >
    > Note: that includes a compiler-generated operator=.
    >
    >
    > Cheers & hth.,
    >
    > - Alf


    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
     
    Alf P. Steinbach, Apr 11, 2009
    #5
  6. Arne Mertz

    Arne Mertz Guest

    Alf P. Steinbach schrieb:
    > * Alf P. Steinbach:
    >> * Arne Mertz:
    >>>
    >>> I could not find any phrase in the standard saying whether the result
    >>> of an explicit conversion is an l-value or an r-value.

    >>
    >> It's an rvalue.

    >
    > More precisely (I didn't register that phrasing) the expression is an
    > rvalue.
    >
    > The result at run time when the expression is evaluated is an object.
    >
    > Objects are neither lvalues nor rvalues, only expressions are.
    >


    Okay, thank you.
    In boost::eek:perators this "shorthand" notation is used for one of the
    operator-templates, thus preventing those templates to be used with
    builtins. Guess I should write a ticket and/or search for a
    workaround :(

    greets
    A
     
    Arne Mertz, Apr 11, 2009
    #6
  7. Arne Mertz

    SG Guest

    On 11 Apr., 18:30, Arne Mertz <> wrote:
    > Alf P. Steinbach wrote:
    > > Perhaps you meant
    > >   return T(u)/t;

    >
    > Yes, sorry.
    >
    > [...]
    >
    > Okay, seems I messed it all up a bit. So another try here:
    >
    > template <class T, class U>
    > T foo(U const& u, T const& t)
    > {
    >    return T(u) /= t;
    > }


    You either write

    return T(u) / t; // suggested previously

    or you write

    T temp = u;
    temp /= t;
    return temp;

    But "/=" doesn't generally work on rvalues. T(u) *is* an rvalue
    expression.

    Cheers!
    SG
     
    SG, Apr 11, 2009
    #7
  8. Arne Mertz

    Arne Mertz Guest

    SG schrieb:
    > On 11 Apr., 18:30, Arne Mertz <> wrote:
    >
    > You either write
    >
    > return T(u) / t; // suggested previously
    >
    > or you write
    >
    > T temp = u;
    > temp /= t;
    > return temp;
    >


    Unfortunately, *I* write nothing there. The function is part of the
    boost libraries (boost/operators.hpp, line 240). It is only used in
    the absence of two #defines, so as a workaround I had to check for
    those defines and set one of them explicitly.

    Greets
    A
     
    Arne Mertz, Apr 11, 2009
    #8
  9. Arne Mertz

    James Kanze Guest

    On Apr 11, 5:13 pm, Arne Mertz <> wrote:
    > Hi all, following example:


    > template <class T, class U>
    > T foo(U const& u, T const& t)
    > {
    > return T temp(u) /= t;
    > }


    > gives me an error "'/=' left operand has to be an l-value" on
    > MSVC 2008 express, if T is a builtin type (e.g. double). In my
    > case, U has an konversion operator to double. If I try the
    > same with T being a builtin class and either providing a
    > konversion ctor for T or providing an konversion operator for
    > U, it works. My question is: is that right according to the
    > standard? I found a line saying that implicit standard
    > conversions result in l-values, but as far as i can see this
    > is an explicitly called user defined conversion or not?


    Alf's already pointed out a couple of errors in your
    formulation: illegal syntax in the example, constructors for a
    build in type. Those aren't nits: copy paste the actual code
    for code, and as for the others: being able to express yourself
    clearly, concisely and precisely in your native language is a
    prerequisite to learning any programming language. (I realize
    that English probably isn't your native language, judging from
    your return address, but in this case, the translation would be
    literal to and from any other language: "Es gibt keinen
    Constructor für eingebaut Type" in German, as well. And if you
    really do have problems with English, the people in
    de.comp.lang.iso-c++ are very friendly as well.)

    Anyway: I don't know where you found anything saying that
    implicit standard conversions result in lvalues. The only
    conversions which result in lvalues are those to references, and
    none of the standard conversions result in a references. The
    only way something like "return T(u) /= t ;" could be legal is
    if T had a user defined conversion operator which returned a
    reference, or if operator/=() was a member function of T (or a
    base class of T). (The latter is actually a frequent case.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 12, 2009
    #9
  10. Arne Mertz

    James Kanze Guest

    On Apr 11, 9:34 pm, Arne Mertz <> wrote:
    > SG schrieb:


    > > On 11 Apr., 18:30, Arne Mertz <> wrote:


    > > You either write


    > > return T(u) / t; // suggested previously


    > > or you write


    > > T temp = u;
    > > temp /= t;
    > > return temp;


    > Unfortunately, *I* write nothing there. The function is part
    > of the boost libraries (boost/operators.hpp, line 240). It is
    > only used in the absence of two #defines, so as a workaround I
    > had to check for those defines and set one of them explicitly.


    Have you actually read the documentation of Boost::eek:perators?
    They provide operators for user defined classes. Not in the
    best way, of course---you really want to use the Barton and
    Nackman trick here, and provide them as friends of a base
    class. But that's not the point here: if you instantiate e.g.
    operator/ with X as the first template argument, then it is a
    pre-condition that X has a member function operator/=.
    Otherwise, you're not using the library as specified.

    Of course, I can't find any way you could reasonably use the
    library as it is specified---you need operator/ to be somewhere
    where ADL will find it, and ADL will not look into namespace
    boost. (That's why the Barton and Nackman trick is preferred.)
    And of course, there really isn't any good reason to not support
    classes with operator/= as a free function---arguably, it should
    be a free function, because that is the only way to make it
    require an lvalue. (On the other hand, operator= can't be a
    free function, so you've lost this aspect anyway, and you might
    as well go ahead and make them all members. I know I usuallly
    do.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 12, 2009
    #10
  11. Arne Mertz

    Arne Mertz Guest

    James Kanze schrieb:
    > On Apr 11, 9:34 pm, Arne Mertz <> wrote:
    >> SG schrieb:

    >
    >>> On 11 Apr., 18:30, Arne Mertz <> wrote:

    >
    >>> You either write

    >
    >>> return T(u) / t; // suggested previously

    >
    >>> or you write

    >
    >>> T temp = u;
    >>> temp /= t;
    >>> return temp;

    >
    >> Unfortunately, *I* write nothing there. The function is part
    >> of the boost libraries (boost/operators.hpp, line 240). It is
    >> only used in the absence of two #defines, so as a workaround I
    >> had to check for those defines and set one of them explicitly.

    >
    > Have you actually read the documentation of Boost::eek:perators?
    > They provide operators for user defined classes. Not in the
    > best way, of course---you really want to use the Barton and
    > Nackman trick here, and provide them as friends of a base
    > class. But that's not the point here: if you instantiate e.g.
    > operator/ with X as the first template argument, then it is a
    > pre-condition that X has a member function operator/=.
    > Otherwise, you're not using the library as specified.


    Well, as far as I can see the documentation says only that the
    operation has to compile, not that operator /= must be a member.

    >
    > Of course, I can't find any way you could reasonably use the
    > library as it is specified---you need operator/ to be somewhere
    > where ADL will find it, and ADL will not look into namespace
    > boost. (That's why the Barton and Nackman trick is preferred.)
    > And of course, there really isn't any good reason to not support
    > classes with operator/= as a free function---arguably, it should
    > be a free function, because that is the only way to make it
    > require an lvalue.


    In my case it is indeed a free function - it is the builtin
    operator/=(double, double). The problem occurs with
    dividable2_left<double, X>, which implements

    double operator-(X const&, double const&) by converting the X into
    double and applying /=

    I know that the mixed arithmetic templates <T,U> should be declared
    base classes of T, not of U, but as T is double I derive U from
    those templates to make the lookup possible. As I said, the short
    form is only used when BOOST_HAS_NRVO and
    BOOST_FORCE_SYMMETRIC_OPERATORS are not #defined so at the moment I
    make sure that one of the two is defined:

    #include <boost/config.hpp>
    #ifndef BOOST_HAS_NRVO
    #define BOOST_FORCE_SYMMETRIC_OPERATORS
    #endif

    #include <boost/operators.hpp>

    But what puzzles me is that if the left template argument is a
    userdefined type with a free operator/=, the problem does not occur:

    class Y {};

    Y& operator/= (Y& lhs, Y const&) { return lhs; }


    struct X : public boost::dividable2_left<Y, X>
    {
    operator Y() const {return Y();}
    };

    //injected by boost:
    //Y boost::eek:perator/ (Y vonst& lhs, X const& rhs)
    //{ return X(lhs) /= rhs; }
    //

    int main()
    {
    X x;
    Y y;
    Y e = x / y;
    }

    greets
    A
     
    Arne Mertz, Apr 12, 2009
    #11
  12. Arne Mertz

    James Kanze Guest

    On Apr 12, 8:41 pm, Arne Mertz <> wrote:
    > James Kanze schrieb:
    > > On Apr 11, 9:34 pm, Arne Mertz <> wrote:
    > >> SG schrieb:


    > >>> On 11 Apr., 18:30, Arne Mertz <> wrote:


    > >>> You either write


    > >>> return T(u) / t; // suggested previously


    > >>> or you write


    > >>> T temp = u;
    > >>> temp /= t;
    > >>> return temp;


    > >> Unfortunately, *I* write nothing there. The function is
    > >> part of the boost libraries (boost/operators.hpp, line
    > >> 240). It is only used in the absence of two #defines, so as
    > >> a workaround I had to check for those defines and set one
    > >> of them explicitly.


    > > Have you actually read the documentation of
    > > Boost::eek:perators? They provide operators for user defined
    > > classes. Not in the best way, of course---you really want
    > > to use the Barton and Nackman trick here, and provide them
    > > as friends of a base class. But that's not the point here:
    > > if you instantiate e.g. operator/ with X as the first
    > > template argument, then it is a pre-condition that X has a
    > > member function operator/=. Otherwise, you're not using the
    > > library as specified.


    > Well, as far as I can see the documentation says only that the
    > operation has to compile, not that operator /= must be a
    > member.


    That's true in the tables, but the introductory documentation
    does make a point of them being member functions. (Of course,
    logically, it should be documented as a constraint.)

    > > Of course, I can't find any way you could reasonably use the
    > > library as it is specified---you need operator/ to be
    > > somewhere where ADL will find it, and ADL will not look into
    > > namespace boost. (That's why the Barton and Nackman trick
    > > is preferred.) And of course, there really isn't any good
    > > reason to not support classes with operator/= as a free
    > > function---arguably, it should be a free function, because
    > > that is the only way to make it require an lvalue.


    > In my case it is indeed a free function - it is the builtin
    > operator/=(double, double). The problem occurs with
    > dividable2_left<double, X>, which implements


    > double operator-(X const&, double const&) by converting the X
    > into double and applying /=


    I'm not sure I understand. You can't overload /= for double,
    double. The compiler won't even consider user defined overloads
    in such cases.

    > I know that the mixed arithmetic templates <T,U> should be
    > declared base classes of T, not of U, but as T is double I
    > derive U from those templates to make the lookup possible. As
    > I said, the short form is only used when BOOST_HAS_NRVO and
    > BOOST_FORCE_SYMMETRIC_OPERATORS are not #defined so at the
    > moment I make sure that one of the two is defined:


    The source is such a confused mess of conditional compilations
    that I can't make heads or tails of it. What I think is that
    you have two variants (after expansion of all the macros):

    T
    operator/( T lhs, U const& rhs )
    {
    return lhs /= rhs ;
    }

    and

    T
    operator/( T const& lhs, U const& rhs )
    {
    T nrv( lhs ) ;
    nrv /= rhs ;
    return nrv ;
    }

    Both of these should work with T == double. (The first isn't
    what I'd consider good coding style, but apparently, it's an
    optimization for compilers which don't support NRVO.)

    The case you're interested in is more complex, however, since
    they do an implicit conversion on the value to the left of the
    /=. There's no way this can work for a built-in type.

    > #include <boost/config.hpp>
    > #ifndef BOOST_HAS_NRVO
    > #define BOOST_FORCE_SYMMETRIC_OPERATORS
    > #endif


    > #include <boost/operators.hpp>


    I think that BOOST_FORCE_SYMMETRIC_OPERATORS is designed to be
    set by you. Just define it, before including any Boost headers,
    and I think you should be OK. (I can't test it, because for my
    compiler here, BOOST_HAS_NRVO is set, systematically, so unless
    I use a hack like the above to undefine it, your code works.)

    > But what puzzles me is that if the left template argument is a
    > user defined type with a free operator/=, the problem does not
    > occur:


    > class Y {};


    > Y& operator/= (Y& lhs, Y const&) { return lhs; }


    > struct X : public boost::dividable2_left<Y, X>
    > {
    > operator Y() const {return Y();}
    > };


    > //injected by boost:
    > //Y boost::eek:perator/ (Y vonst& lhs, X const& rhs)
    > //{ return X(lhs) /= rhs; }
    > //


    > int main()
    > {
    > X x;
    > Y y;
    > Y e = x / y;
    >
    > }


    Yes it does.

    In the beginning of the thread, you mentioned VC++, I think.
    I'm not sure, but I seem to recall hearing that VC++ doesn't
    enforce the rule about not binding a temporary to a non-const
    reference. In which case, the above will work (but the built-in
    operator won't, because the rules for lvalues are enforced).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 13, 2009
    #12
  13. Arne Mertz

    Arne Mertz Guest

    James Kanze schrieb:
    > On Apr 12, 8:41 pm, Arne Mertz <> wrote:
    >> James Kanze schrieb:


    >> In my case it is indeed a free function - it is the builtin
    >> operator/=(double, double). The problem occurs with
    >> dividable2_left<double, X>, which implements

    >
    >> double operator-(X const&, double const&) by converting the X
    >> into double and applying /=

    >
    > I'm not sure I understand. You can't overload /= for double,
    > double. The compiler won't even consider user defined overloads
    > in such cases.
    >


    Actually I don't try to overload operator/= for double, double. All
    I have to do for the dividable2_left<double,X> is provide the
    conversion from X to double.

    >> I know that the mixed arithmetic templates <T,U> should be
    >> declared base classes of T, not of U, but as T is double I
    >> derive U from those templates to make the lookup possible. As
    >> I said, the short form is only used when BOOST_HAS_NRVO and
    >> BOOST_FORCE_SYMMETRIC_OPERATORS are not #defined so at the
    >> moment I make sure that one of the two is defined:

    >
    > The source is such a confused mess of conditional compilations
    > that I can't make heads or tails of it. What I think is that
    > you have two variants (after expansion of all the macros):
    >
    > T
    > operator/( T lhs, U const& rhs )
    > {
    > return lhs /= rhs ;
    > }
    >
    > and
    >
    > T
    > operator/( T const& lhs, U const& rhs )
    > {
    > T nrv( lhs ) ;
    > nrv /= rhs ;
    > return nrv ;
    > }
    >

    these are not the implementations of the operator I have problems
    with. its not T op/(T, U), but T op/(U, T).
    The two versions of the BOOST_OPERATOR2_LEFT macros are

    #if defined(BOOST_HAS_NRVO) || \
    defined(BOOST_FORCE_SYMMETRIC_OPERATORS)

    friend T operator OP( const U& lhs, const T& rhs )
    { T nrv( lhs ); nrv OP##= rhs; return nrv; }


    #else

    friend T operator OP( const U& lhs, const T& rhs )
    { return T( lhs ) OP##= rhs; }

    #endif

    the latter is the version I am having problems with, if T is double.

    > Both of these should work with T == double. (The first isn't
    > what I'd consider good coding style, but apparently, it's an
    > optimization for compilers which don't support NRVO.)
    >
    > The case you're interested in is more complex, however, since
    > they do an implicit conversion on the value to the left of the
    > /=. There's no way this can work for a built-in type.
    >


    Yes, for the op(T,U) operators thats OK, but for the op(U,T)
    apparently it is not, because the U has to be converted into T,
    resulting in the problems I described. And note the comment to the
    non-nrvo version:

    // [...] Note that the implementation of
    // BOOST_OPERATOR2_LEFT(NAME) only looks cool, but doesn't provide
    // optimization opportunities to the compiler :)

    [snip]

    >> But what puzzles me is that if the left template argument is a
    >> user defined type with a free operator/=, the problem does not
    >> occur:

    >
    >> class Y {};

    >
    >> Y& operator/= (Y& lhs, Y const&) { return lhs; }

    >
    >> struct X : public boost::dividable2_left<Y, X>
    >> {
    >> operator Y() const {return Y();}
    >> };

    >
    >> //injected by boost:
    >> //Y boost::eek:perator/ (Y vonst& lhs, X const& rhs)
    >> //{ return X(lhs) /= rhs; }
    >> //

    >
    >> int main()
    >> {
    >> X x;
    >> Y y;
    >> Y e = x / y;
    >>
    >> }

    >
    > Yes it does.
    >
    > In the beginning of the thread, you mentioned VC++, I think.
    > I'm not sure, but I seem to recall hearing that VC++ doesn't
    > enforce the rule about not binding a temporary to a non-const
    > reference. In which case, the above will work (but the built-in
    > operator won't, because the rules for lvalues are enforced).
    >


    Ah okay, so it's a non-conformity to the standard that makes it work
    on MSVC?

    greets
    A
     
    Arne Mertz, Apr 13, 2009
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Oodini
    Replies:
    1
    Views:
    1,836
    Keith Thompson
    Sep 27, 2005
  2. Kavya
    Replies:
    2
    Views:
    643
    Kavya
    Oct 31, 2006
  3. Replies:
    1
    Views:
    468
    Sylvester Hesp
    May 16, 2007
  4. PSN
    Replies:
    8
    Views:
    663
    Paul N
    Jun 18, 2011
  5. bdb112
    Replies:
    2
    Views:
    316
    Chris Torek
    Jul 2, 2011
Loading...

Share This Page