Compiler error with friend

Discussion in 'C++' started by Adrian, Jan 13, 2011.

  1. Adrian

    Adrian Guest

    Hi Guys,

    I obviously have a mistake in this - I just cant seem to see it for
    looking this morning.

    I've tried various forms of the friend declaration but the compiler
    seems to be ignoring them all.

    Why wont the following compile when using namespaces

    TIA

    Adrian

    adrianc@dluadrianc:~> g++ -Wall -ansi -pedantic -Wextra -Weffc++ foo.cc
    foo.cc:18:12: warning: unused parameter 'os'
    foo.cc:32:5: warning: unused parameter 'argc'
    foo.cc:32:5: warning: unused parameter 'argv'

    adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
    -Weffc++ foo.cc
    foo.cc:18:12: warning: unused parameter 'os'
    foo.cc:32:5: warning: unused parameter 'argc'
    foo.cc:32:5: warning: unused parameter 'argv'
    foo.cc: In function 'std::eek:stream& operator<<(std::eek:stream&, const
    level1::level2::foo&)':
    foo.cc:18:12: error: 'void level1::level2::foo::print(std::eek:stream&)
    const' is private
    foo.cc:43:16: error: within this context



    #include <iostream>

    #ifdef NAMESPACES
    namespace level1
    {
    namespace level2
    {
    #endif
    class foo
    {
    public:
    #ifdef NAMESPACES
    friend std::eek:stream &operator<<(std::eek:stream &os, const
    ::level1::level2::foo &rhs);
    #else
    friend std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs);
    #endif
    private:
    void print(std::eek:stream &os) const
    {
    }
    };
    #ifdef NAMESPACES
    }}
    #endif

    #ifdef NAMESPACES
    std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs);
    #else
    std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs);
    #endif

    int main(int argc, char *argv[])
    {
    return 0;
    }

    #ifdef NAMESPACES
    std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs)
    #else
    std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs)
    #endif
    {
    rhs.print(os);
    return os;
    }
    Adrian, Jan 13, 2011
    #1
    1. Advertising

  2. On 01/13/2011 09:26 AM, Adrian wrote:
    > Hi Guys,
    >
    > I obviously have a mistake in this - I just cant seem to see it for
    > looking this morning.
    >
    > I've tried various forms of the friend declaration but the compiler
    > seems to be ignoring them all.
    >
    > Why wont the following compile when using namespaces
    >
    > TIA
    >
    > Adrian
    >
    > adrianc@dluadrianc:~> g++ -Wall -ansi -pedantic -Wextra -Weffc++ foo.cc
    > foo.cc:18:12: warning: unused parameter 'os'
    > foo.cc:32:5: warning: unused parameter 'argc'
    > foo.cc:32:5: warning: unused parameter 'argv'
    >
    > adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
    > -Weffc++ foo.cc
    > foo.cc:18:12: warning: unused parameter 'os'
    > foo.cc:32:5: warning: unused parameter 'argc'
    > foo.cc:32:5: warning: unused parameter 'argv'
    > foo.cc: In function 'std::eek:stream& operator<<(std::eek:stream&, const
    > level1::level2::foo&)':
    > foo.cc:18:12: error: 'void level1::level2::foo::print(std::eek:stream&)
    > const' is private
    > foo.cc:43:16: error: within this context
    >
    >
    >
    > #include <iostream>
    >
    > #ifdef NAMESPACES
    > namespace level1
    > {
    > namespace level2
    > {
    > #endif
    > class foo
    > {
    > public:
    > #ifdef NAMESPACES
    > friend std::eek:stream &operator<<(std::eek:stream &os, const
    > ::level1::level2::foo &rhs);


    This declaration of 'operator<<' is in the level1::level2 namespace. If
    you want it to be in the anonymous namespace, you'll have to declare it
    as 'friend std::eek:stream& ::eek:perator<<(...)'.

    > #else
    > friend std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs);
    > #endif
    > private:
    > void print(std::eek:stream &os) const
    > {
    > }
    > };
    > #ifdef NAMESPACES
    > }}
    > #endif
    >
    > #ifdef NAMESPACES
    > std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs);
    > #else
    > std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs);
    > #endif
    >
    > int main(int argc, char *argv[])
    > {
    > return 0;
    > }
    >
    > #ifdef NAMESPACES
    > std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs)
    > #else
    > std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs)
    > #endif
    > {
    > rhs.print(os);
    > return os;
    > }
    Kevin P. Fleming, Jan 13, 2011
    #2
    1. Advertising

  3. On 1/13/2011 10:26 AM, Adrian wrote:
    > Hi Guys,
    >
    > I obviously have a mistake in this - I just cant seem to see it for
    > looking this morning.
    >
    > I've tried various forms of the friend declaration but the compiler
    > seems to be ignoring them all.
    >
    > Why wont the following compile when using namespaces
    >
    > TIA
    >
    > Adrian
    >
    > adrianc@dluadrianc:~> g++ -Wall -ansi -pedantic -Wextra -Weffc++ foo.cc
    > foo.cc:18:12: warning: unused parameter 'os'
    > foo.cc:32:5: warning: unused parameter 'argc'
    > foo.cc:32:5: warning: unused parameter 'argv'
    >
    > adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
    > -Weffc++ foo.cc
    > foo.cc:18:12: warning: unused parameter 'os'
    > foo.cc:32:5: warning: unused parameter 'argc'
    > foo.cc:32:5: warning: unused parameter 'argv'
    > foo.cc: In function 'std::eek:stream& operator<<(std::eek:stream&, const
    > level1::level2::foo&)':
    > foo.cc:18:12: error: 'void level1::level2::foo::print(std::eek:stream&)
    > const' is private
    > foo.cc:43:16: error: within this context
    >
    >
    >
    > #include <iostream>
    >
    > #ifdef NAMESPACES
    > namespace level1
    > {
    > namespace level2
    > {
    > #endif
    > class foo
    > {
    > public:
    > #ifdef NAMESPACES
    > friend std::eek:stream &operator<<(std::eek:stream &os, const
    > ::level1::level2::foo &rhs);
    > #else
    > friend std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs);
    > #endif


    You're going to avoid many problems if you declare those functions where
    they are supposed to reside *before* using their name in a friend
    declaration. Try it. Before your present 'namespace level1' write the
    function "prototype":

    std::eek:stream &operator<<(std::eek:stream &os,
    const level1::level2::foo &rhs);

    As you can see, you will need the have 'foo' declared as well. In order
    to do that, *before* the function declaration, write

    namespace level1 { namespace level2 { class foo; } }

    which will declare that 'foo' is a class inside those namespaces. That
    should take care of it.

    Namespaces can be re-opened in a translation unit (or even across them).
    The forward-declaration of 'foo' will allow the compiler to create a
    function declaration of the proper type. The 'friend' declaration then
    will connect the class with the previously declared function. Then,
    when you finally define the function, the compiler will know that you meant.

    > private:
    > void print(std::eek:stream &os) const
    > {
    > }
    > };
    > #ifdef NAMESPACES
    > }}
    > #endif
    >
    > #ifdef NAMESPACES
    > std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs);
    > #else
    > std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs);
    > #endif
    >
    > int main(int argc, char *argv[])
    > {
    > return 0;
    > }
    >
    > #ifdef NAMESPACES
    > std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs)
    > #else
    > std::eek:stream &operator<<(std::eek:stream &os, const foo &rhs)
    > #endif
    > {
    > rhs.print(os);
    > return os;
    > }


    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jan 13, 2011
    #3
  4. Adrian

    Adrian Guest

    On 01/13/2011 08:34 AM, Kevin P. Fleming wrote:
    > This declaration of 'operator<<' is in the level1::level2 namespace. If
    > you want it to be in the anonymous namespace, you'll have to declare it
    > as 'friend std::eek:stream& ::eek:perator<<(...)'.

    Hi Keven,

    Tried that as well. Different error - but didnt work. :-(

    12 #ifdef NAMESPACES
    13 friend std::eek:stream &::eek:perator<<(std::eek:stream &os, const
    ::level1::level2::foo &rhs);
    14 #else

    adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
    -Weffc++ foo.cc
    foo.cc:13:91: error: 'std::eek:stream& operator<<(std::eek:stream&, const
    level1::level2::foo&)' should have been declared inside '::'
    foo.cc:18:12: warning: unused parameter 'os'
    foo.cc:32:5: warning: unused parameter 'argc'
    foo.cc:32:5: warning: unused parameter 'argv'
    Adrian, Jan 13, 2011
    #4
  5. Adrian

    Adrian Guest

    Thanks Guys, got it now with combination of forward decl and marking
    operator<< as global scope. So basically a combination of Victor's and
    Kevin's replies.



    #include <iostream>

    namespace level1 {namespace level2 { class foo; }}
    std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs);

    namespace level1
    {
    namespace level2
    {
    class foo
    {
    public:
    friend std::eek:stream &::eek:perator<<(std::eek:stream &os, const foo &rhs);
    private:
    void print(std::eek:stream &os) const
    {
    }
    };
    }}



    int main(int argc, char *argv[])
    {
    return 0;
    }

    std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo &rhs)
    {
    rhs.print(os);
    return os;
    }
    Adrian, Jan 13, 2011
    #5
  6. Adrian wrote:
    > Thanks Guys, got it now with combination of forward decl and marking
    > operator<< as global scope. So basically a combination of Victor's and
    > Kevin's replies.


    Actually, Leigh's suggestion was the best of the three.

    > namespace level1 {namespace level2 { class foo; }}
    > std::eek:stream &operator<<(std::eek:stream &os, const level1::level2::foo
    > &rhs);
    >
    > namespace level1
    > {
    > namespace level2
    > {
    > class foo
    > {
    > public:
    > friend std::eek:stream &
    > ::eek:perator<<(std::eek:stream &os, const foo &rhs);
    > private:
    > void print(std::eek:stream &os) const
    > {
    > }
    > };
    > }}

    [...]
    > std::eek:stream &
    > operator<<(std::eek:stream &os, const level1::level2::foo &rhs)
    > {
    > rhs.print(os);
    > return os;
    > }


    Actually, I'd like to ask why you want the operator<< overload to be in
    the global namespace? There is no need for this due to ADL (Argument-
    Dependent Lookup aka Koenig Lookup), which basically means it will be
    found even if it is in the namespace, just by the parameters given to it.

    Additionally, you can declare and define the operator inline, which saves
    quite a bit of typing. Since it also is very short, it doesn't hurt that
    it is inline either.

    Uli
    Ulrich Eckhardt, Jan 13, 2011
    #6
  7. Adrian

    James Kanze Guest

    On Jan 13, 3:44 pm, Leigh Johnston <> wrote:
    > On 13/01/2011 15:26, Adrian wrote:


    [...]
    > Use friend name injection; that should solve your problem
    > (there is no need to define operator<< at global scope due to
    > ADL).


    I'm not sure about your vocabulary here. What do you mean by
    "friend name injection"? The names of a friend used to be
    injected into the surrounding scope, but this was removed from
    the standard. ADL does do a sort of injection, but this is
    limited. (It will work in the case of operator<<. But it can
    fail to work in some other special cases. ADT only kicks in
    once the compiler has found a function. ADT will add to the
    overload set, but it won't be used if the initial overload set
    is empty.)

    --
    James Kanze
    James Kanze, Jan 13, 2011
    #7
  8. Adrian

    James Kanze Guest

    On Jan 13, 7:48 pm, Leigh Johnston <> wrote:
    > On 13/01/2011 19:38, James Kanze wrote:
    > > On Jan 13, 3:44 pm, Leigh Johnston<> wrote:
    > >> On 13/01/2011 15:26, Adrian wrote:


    > > [...]
    > >> Use friend name injection; that should solve your problem
    > >> (there is no need to define operator<< at global scope due to
    > >> ADL).


    > > I'm not sure about your vocabulary here. What do you mean by
    > > "friend name injection"? The names of a friend used to be
    > > injected into the surrounding scope, but this was removed from
    > > the standard. ADL does do a sort of injection, but this is
    > > limited. (It will work in the case of operator<<. But it can
    > > fail to work in some other special cases. ADT only kicks in
    > > once the compiler has found a function. ADT will add to the
    > > overload set, but it won't be used if the initial overload set
    > > is empty.)


    > struct foo
    > {
    > friend void friend_name_injection(const foo& a) { std::cout <<
    > a.iPrivateBits; }
    > public:
    > foo() : iPrivateBits(42) {}
    > private:
    > int iPrivateBits;
    > };


    > int main()
    > {
    > foo o;
    > friend_name_injection(o);
    > }


    This doesn't use friend name injection, but ADL. And while this
    particular example does seem to work, I had a problem recently
    with something very similar, which failed to compile with g++.
    (But looking at it, my case was slightly different.)

    Friend name injection, as defined in the ARM and other
    prestandard documents, would have resulted in
    friend_name_injection being found even without ADL (which didn't
    exist back then); a friend declaration always injected the name
    into the surrounding scope (or back then, in pre namespace days,
    file scope).

    There's an issue I'm not too sure about (although I know what
    compilers actually do, and I don't expect that to change). ADL
    is only used for the postfix-expression of a function call. But
    the meaning of () is context dependent. Given the expression
    friend_name_injection(o), above, how does the compiler decide
    whether the () is a function call, or part of an "Explicit type
    conversion (functional notation)"? The obvious answer is that
    it is a function call, because friend_name_injection is the name
    of a function. The compiler cannot find friend_name_injection
    (to know that it is function, and not the name of a type) until
    it uses ADL, and it cannot use ADL until it knows that
    friend_name_injection is not the name of a type.

    I think I'll raise the issue in comp.std.c++. Given the
    expression `f(a)', all of the compilers I know assume a function
    call until proven otherwise, but I can't find anything in the
    standard to support this.

    > Are you claiming that the above code will become illegal in
    > C++0x? If not then how can it be that friend name injection
    > is being removed?


    No, but the reason it works is ADL, and not friend name
    injection.

    --
    James Kanze
    James Kanze, Jan 14, 2011
    #8
  9. On 01/14/2011 07:20 AM, Leigh Johnston wrote:
    > On 14/01/2011 13:03, Leigh Johnston wrote:
    >> On 14/01/2011 12:48, Leigh Johnston wrote:
    >>> On 14/01/2011 09:07, James Kanze wrote:
    >>>> On Jan 13, 7:48 pm, Leigh Johnston<> wrote:
    >>>>> On 13/01/2011 19:38, James Kanze wrote:
    >>>>>> On Jan 13, 3:44 pm, Leigh Johnston<> wrote:
    >>>>>>> On 13/01/2011 15:26, Adrian wrote:
    >>>>
    >>>>>> [...]
    >>>>>>> Use friend name injection; that should solve your problem
    >>>>>>> (there is no need to define operator<< at global scope due to
    >>>>>>> ADL).
    >>>>
    >>>>>> I'm not sure about your vocabulary here. What do you mean by
    >>>>>> "friend name injection"? The names of a friend used to be
    >>>>>> injected into the surrounding scope, but this was removed from
    >>>>>> the standard. ADL does do a sort of injection, but this is
    >>>>>> limited. (It will work in the case of operator<<. But it can
    >>>>>> fail to work in some other special cases. ADT only kicks in
    >>>>>> once the compiler has found a function. ADT will add to the
    >>>>>> overload set, but it won't be used if the initial overload set
    >>>>>> is empty.)
    >>>>
    >>>>> struct foo
    >>>>> {
    >>>>> friend void friend_name_injection(const foo& a) { std::cout<<
    >>>>> a.iPrivateBits; }
    >>>>> public:
    >>>>> foo() : iPrivateBits(42) {}
    >>>>> private:
    >>>>> int iPrivateBits;
    >>>>> };
    >>>>
    >>>>> int main()
    >>>>> {
    >>>>> foo o;
    >>>>> friend_name_injection(o);
    >>>>> }
    >>>>
    >>>> This doesn't use friend name injection, but ADL. And while this
    >>>> particular example does seem to work, I had a problem recently
    >>>> with something very similar, which failed to compile with g++.
    >>>> (But looking at it, my case was slightly different.)
    >>>>
    >>>> Friend name injection, as defined in the ARM and other
    >>>> prestandard documents, would have resulted in
    >>>> friend_name_injection being found even without ADL (which didn't
    >>>> exist back then); a friend declaration always injected the name
    >>>> into the surrounding scope (or back then, in pre namespace days,
    >>>> file scope).
    >>>>
    >>>> There's an issue I'm not too sure about (although I know what
    >>>> compilers actually do, and I don't expect that to change). ADL
    >>>> is only used for the postfix-expression of a function call. But
    >>>> the meaning of () is context dependent. Given the expression
    >>>> friend_name_injection(o), above, how does the compiler decide
    >>>> whether the () is a function call, or part of an "Explicit type
    >>>> conversion (functional notation)"? The obvious answer is that
    >>>> it is a function call, because friend_name_injection is the name
    >>>> of a function. The compiler cannot find friend_name_injection
    >>>> (to know that it is function, and not the name of a type) until
    >>>> it uses ADL, and it cannot use ADL until it knows that
    >>>> friend_name_injection is not the name of a type.
    >>>>
    >>>> I think I'll raise the issue in comp.std.c++. Given the
    >>>> expression `f(a)', all of the compilers I know assume a function
    >>>> call until proven otherwise, but I can't find anything in the
    >>>> standard to support this.
    >>>>
    >>>>> Are you claiming that the above code will become illegal in
    >>>>> C++0x? If not then how can it be that friend name injection
    >>>>> is being removed?
    >>>>
    >>>> No, but the reason it works is ADL, and not friend name
    >>>> injection.
    >>>>
    >>>
    >>> Why can't you just admit when you are wrong? The code I gave is an
    >>> example of friend name injection; from Wikipedia:
    >>>
    >>> "a C++ feature called "friend name injection", in which an in-class
    >>> declaration of a friend function made the function name visible in the
    >>> immediately surrounding namespace scope (possibly the global scope)."
    >>>
    >>> The fact that ADL is being used does not mean that friend name injection
    >>> is not also happening. Friend name injection has not been removed.
    >>>

    >>
    >> I apologize; you are correct of course and I am wrong as the following
    >> illegal code shows:
    >>
    >> struct foo
    >> {
    >> friend void friend_name_injection() { std::cout << "friend name
    >> injection"; }
    >> public:
    >> foo() : iPrivateBits(42) {}
    >> private:
    >> int iPrivateBits;
    >> };
    >>
    >> int main()
    >> {
    >> friend_name_injection(); // error
    >> }
    >>
    >> If injection was actually happening the error would not be an error.
    >>

    >
    > Actually my correction was wrong; instead we were both initially
    > correct; *injection* is happening but the function is only accessible
    > via ADL:
    >
    > struct foo
    > {
    > public:
    > friend void friend_name_injection() { std::cout << "friend name
    > injection"; }
    > public:
    > foo() : iPrivateBits(42) {}
    > private:
    > int iPrivateBits;
    > };
    >
    > void friend_name_injection() // error, function already has a body.
    > {
    > }


    That seems a bit strange... if the function can only be accessed through
    ADL, then there's no value in injecting its name into the enclosing
    namespace, is there?
    Kevin P. Fleming, Jan 14, 2011
    #9
  10. Adrian

    James Kanze Guest

    On Jan 14, 12:48 pm, Leigh Johnston <> wrote:
    > On 14/01/2011 09:07, James Kanze wrote:


    [...]
    > > No, but the reason it works is ADL, and not friend name
    > > injection.


    > Why can't you just admit when you are wrong?


    Because I'm not. I was actually there when freind name
    injection was voted out.

    > The code I gave is an
    > example of friend name injection; from Wikipedia:


    > "a C++ feature called "friend name injection", in which an in-class
    > declaration of a friend function made the function name visible in the
    > immediately surrounding namespace scope (possibly the global scope)."


    So the Wikipedia is wrong. (Nothing new there.) The reference
    for C++ is not the Wikipedia, but the C++ standard. The only
    injection defined in the C++ is class name injection: the name
    of a class is injected into that class.

    > The fact that ADL is being used does not mean that friend name
    > injection is not also happening. Friend name injection has
    > not been removed.


    It's certainly not present in the current (C++03) standard. It
    wasn't present in C++98 either, although it was present in the
    ARM (1989, I think).

    --
    James Kanze
    James Kanze, Jan 14, 2011
    #10
  11. Adrian

    James Kanze Guest

    On Jan 14, 1:20 pm, Leigh Johnston <> wrote:
    > On 14/01/2011 13:03, Leigh Johnston wrote:


    [...]
    > > I apologize;


    Accepted.

    [...]
    > Actually my correction was wrong; instead we were both initially
    > correct; *injection* is happening but the function is only accessible
    > via ADL:


    > struct foo
    > {
    > public:
    > friend void friend_name_injection() { std::cout << "friend name
    > injection"; }
    > public:
    > foo() : iPrivateBits(42) {}
    > private:
    > int iPrivateBits;


    > };


    > void friend_name_injection() // error, function already has a body.
    > {
    > }


    That's not injection, at least not in the sense used for friend
    name injection in the ARM, nor for class name injection in the
    current standard. But you're right that strange things are
    happening. The friend function is defined in the namespace,
    even if its name has not been injected (and is not visible).
    You can'd define it again, because of the one definition rule;
    it does exist, even if its name is not visible.

    --
    James Kanze
    James Kanze, Jan 14, 2011
    #11
  12. Adrian

    James Kanze Guest

    On Jan 14, 7:56 pm, Leigh Johnston <> wrote:
    > On 14/01/2011 18:44, James Kanze wrote:
    > > On Jan 14, 1:20 pm, Leigh Johnston<> wrote:
    > >> On 14/01/2011 13:03, Leigh Johnston wrote:


    > > [...]
    > > That's not injection, at least not in the sense used for friend
    > > name injection in the ARM, nor for class name injection in the
    > > current standard. But you're right that strange things are
    > > happening. The friend function is defined in the namespace,
    > > even if its name has not been injected (and is not visible).
    > > You can'd define it again, because of the one definition rule;
    > > it does exist, even if its name is not visible.


    > So what term would you use for this if not "friend name injection"?
    > "Friend definition" as opposed to "friend declaration" perhaps?


    That's a good question. I don't know. The standard doesn't use
    any name for it; it just says that the name will be found in
    this context, and not in some other context. In the discussions
    in the standards committee, name injection means that the name
    will be found in all contexts in which name lookup includes that
    scope. In this case, we have:

    -- The name will be found in ADL, but not in other name
    lookups. (In ADL, it will be found "as if" name injection
    had occured.)

    -- The name is defined in the given scope, even if it isn't
    visible. I don't think this is a real problem (unlike the
    issue of ADL); whether something is defined or not is more
    or less independent of visibility. (If I define a function
    f() in global scope a.cpp, it isn't visible in other
    translation units, but it is still defined in global scope,
    and a second definition violates the one definition rule.)

    I really don't know how to describe the first case. Conditional
    name injection would seem a valid description to me, even if the
    standard doesn't talk about name injection.

    --
    James Kanze
    James Kanze, Jan 15, 2011
    #12
    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. Yan
    Replies:
    0
    Views:
    1,107
  2. Jack Wright
    Replies:
    5
    Views:
    604
    Shiv Kumar
    Jan 19, 2004
  3. Ram
    Replies:
    0
    Views:
    2,804
  4. Replies:
    2
    Views:
    1,879
  5. Peter
    Replies:
    2
    Views:
    259
    Öö Tiib
    Jun 6, 2013
Loading...

Share This Page