Allowing function pointer code to work on a member function

Discussion in 'C++' started by Enquiries, Hopkins Research, Oct 22, 2005.

  1. Hi all

    I have a conundrum that is puzzling me.

    I have a large codebase in C that I am converting to C++ as fast as possible
    (i.e. slowly because I keep learning new idioms and stumbling with C++
    'features'). One part of the C code is some optimisation functions that
    expect a pointer to a function which is sent an array of doubles and returns
    a double i.e. simplified..

    void optimise( double (*funk)( double* ) );

    I now have a bunch of classes with member functions which also take double*
    and return double that I want to use in this optimiser, but the compiler
    won't let me because:

    error: argument of type 'double (namespace::class::)(double*)' does not
    match 'double (*)(double*)'

    OK - I hadn't thought about that but felt there must be an easy answer.
    However, I have tried declaring the functions in question as friends (but
    the class members that the functions use are no longer available) and
    sending 'pointers' to them a la BS TCPPPL p.419:

    typedef double (class::*Pstd_mem)( double* pv );
    Pstd_mem p = &class::eek:pt_ll;

    ...but nothing I have tried so far works and I am running out of ideas. Can
    any C++ gurus out there suggest a solution (that is hopefully reliable and
    efficient)?

    TIA and please CC replies here

    Michael


    _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

    _/ _/ _/_/_/ Hopkins Research Ltd
    _/ _/ _/ _/
    _/_/_/_/ _/_/_/ http://www.hopkins-research.com/
    _/ _/ _/ _/
    _/ _/ _/ _/ 'touch the future'

    _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/



    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Enquiries, Hopkins Research, Oct 22, 2005
    #1
    1. Advertising

  2. Enquiries, Hopkins Research wrote:
    > I have a large codebase in C that I am converting to C++ as fast as
    > possible (i.e. slowly because I keep learning new idioms and
    > stumbling with C++ 'features'). One part of the C code is some
    > optimisation functions that expect a pointer to a function which is
    > sent an array of doubles and returns a double i.e. simplified..
    >
    > void optimise( double (*funk)( double* ) );
    >
    > I now have a bunch of classes with member functions which also take
    > double* and return double that I want to use in this optimiser, but
    > the compiler won't let me because:
    >
    > error: argument of type 'double (namespace::class::)(double*)' does
    > not match 'double (*)(double*)'


    They are incompatible.

    See FAQ about pointers to members. You can find the FAQ here:
    http://www.parashift.com/c -faq-lite/

    > [..]


    If you'll have questions after reading the FAQ, do ask them.

    V
    Victor Bazarov, Oct 22, 2005
    #2
    1. Advertising

  3. Enquiries, Hopkins Research wrote:
    > Hi all
    >
    > I have a conundrum that is puzzling me.
    >
    > I have a large codebase in C that I am converting to C++ as fast as possible
    > (i.e. slowly because I keep learning new idioms and stumbling with C++
    > 'features'). One part of the C code is some optimisation functions that
    > expect a pointer to a function which is sent an array of doubles and returns
    > a double i.e. simplified..
    >
    > void optimise( double (*funk)( double* ) );
    >
    > I now have a bunch of classes with member functions which also take double*
    > and return double that I want to use in this optimiser, but the compiler
    > won't let me because:
    >
    > error: argument of type 'double (namespace::class::)(double*)' does not
    > match 'double (*)(double*)'
    >
    > OK - I hadn't thought about that but felt there must be an easy answer.
    > However, I have tried declaring the functions in question as friends (but
    > the class members that the functions use are no longer available) and
    > sending 'pointers' to them a la BS TCPPPL p.419:
    >
    > typedef double (class::*Pstd_mem)( double* pv );
    > Pstd_mem p = &class::eek:pt_ll;
    >
    > ..but nothing I have tried so far works and I am running out of ideas. Can
    > any C++ gurus out there suggest a solution (that is hopefully reliable and
    > efficient)?


    Free functions and member functions are different. See
    http://www.parashift.com/c -faq-lite/pointers-to-members.html,
    especially 33.2. While you're there, read the whole faq, it may help
    you.


    Jonathan


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Jonathan Mcdougall, Oct 22, 2005
    #3
  4. On Sat, 22 Oct 2005 13:48:30 -0400, "Victor Bazarov" <>
    wrote:

    >> I now have a bunch of classes with member functions which also take
    >> double* and return double that I want to use in this optimiser, but
    >> the compiler won't let me because:
    >>
    >> error: argument of type 'double (namespace::class::)(double*)' does
    >> not match 'double (*)(double*)'

    >
    >They are incompatible.


    But you can use them to point to _static_ member functions, which may satisify
    the OP's goal.

    -dr
    Dave Rahardja, Oct 23, 2005
    #4
  5. If I got it correct, you did this:

    class SomeClass
    {
    public:

    double OptimizeCallback(double*) { /* ... */ }
    };

    typedef double (SomeClass::*Pstd_mem)( double* pv );

    // somewhere in the code
    Pstd_mem p = &SomeClass::OptimizeCallback;
    optimise(p);

    As previous 3 posters replied, there is a distinction between a
    non-member function and a member function. The distinction is that
    latter one needs an additional "this" pointer (something like, "mov
    ecx, this", in x86 assembly). In C++, there is no (standard and
    reliable) way to know, at compile time, where the function is going to
    be located.

    Valentin's answers are cool. I'm not keen with libraries, and I didn't
    know whether boost has such a thing. But in that case, you need to use
    boost, and probably you'll need to ship boost libary (.so or .dll)
    along with your binary.

    There ways, arguably efficient and reliable, but they are compiler and
    platform dependent. If you don't have a portability concern, I think we
    can solve this problem. But again, these ways are not supported by
    standard, so generated executable may not run properly, next time you
    compile it with newer version of your current compiler.

    What I thought, for example, is first defining an "interface", which
    could be thought as a "struct of function pointers" in C, derive
    classes from this interface, write a template adapter class that
    returns pointer to the member function (forcibly and tricky, through
    vtable offset), pass this pointer to optimise() as if it is the double
    (funk*)(double*). Since standard doesn't define vtable layout, the code
    won't be portable, and it may need some more tailoring, if your classes
    have different inheritance model (multiple, virtual, etc). As Valentin
    pointed out, this may become difficult to implement for more complex
    scenarios. Again, I want to point out that I am not really sure how
    safe it is! Test good and ask your compiler vendor, if you intend to
    use this:

    For Visual C++: (I guess it works as of VC++ 6.0)

    typedef double(*PFUNK)(double*);

    void optimise(PFUNK pf)
    {
    double d = 3.0;
    pf(&d);
    }


    // Interface definition
    struct IOptimizable
    {
    virtual double OptimizeCallback(double* p) = 0;
    };

    // your class will derive from IOptimizable interface
    class SomeClass : public IOptimizable
    {
    public:
    virtual double OptimizeCallback(double* pdbl)
    {
    cout << *pdbl << endl;
    return *pdbl;
    }
    };

    // adapter class, returns a pointer to the member function.
    template<class T>
    class OptimizeAdapter
    {
    const T* m_pt;
    public:
    explicit OptimizeAdapter(const T* pt)
    :m_pt(pt)
    {
    }
    operator PFUNK()
    {
    IOptimizable const* popt = static_cast<IOptimizable
    const*>(m_pt);
    void* pvtbl = ((void**)popt)[0]; // vtable is at offset 0
    return (PFUNK)((void**)pvtbl)[0]; // one-and-the-only function
    is at offset 0
    }
    };

    int main()
    {
    SomeClass r;
    OptimizeAdapter<SomeClass> adapt(&r);
    optimise(adapt);
    return 0;
    }

    One more point; the object of type SomeClass should live until
    optimise() returns. Otherwise, all bets are off (undefined), as far as
    I know.

    I used an adapter class, because you may need further additions and
    fine tuning before returning function pointer.

    Please let me know, if you intend to use and whether it works :)

    Ismail


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Ismail Pazarbasi, Oct 23, 2005
    #5
  6. Enquiries, Hopkins Research

    Kai-Uwe Bux Guest

    Enquiries, Hopkins Research wrote:

    >
    >
    > Hi all
    >
    > I have a conundrum that is puzzling me.
    >
    > I have a large codebase in C that I am converting to C++ as fast as
    > possible (i.e. slowly because I keep learning new idioms and stumbling
    > with C++
    > 'features'). One part of the C code is some optimisation functions that
    > expect a pointer to a function which is sent an array of doubles and
    > returns a double i.e. simplified..
    >
    > void optimise( double (*funk)( double* ) );
    >
    > I now have a bunch of classes with member functions which also take
    > double* and return double that I want to use in this optimiser, but the
    > compiler won't let me because:
    >
    > error: argument of type 'double (namespace::class::)(double*)' does not
    > match 'double (*)(double*)'
    >
    > OK - I hadn't thought about that but felt there must be an easy answer.
    > However, I have tried declaring the functions in question as friends (but
    > the class members that the functions use are no longer available) and
    > sending 'pointers' to them a la BS TCPPPL p.419:
    >
    > typedef double (class::*Pstd_mem)( double* pv );
    > Pstd_mem p = &class::eek:pt_ll;
    >
    > ..but nothing I have tried so far works and I am running out of ideas.
    > Can any C++ gurus out there suggest a solution (that is hopefully reliable
    > and efficient)?

    [snip]

    Others have already pointed out the reason for your problem. Here is a
    workaround:


    #include <iostream>
    #include <memory>
    #include <stdexcept>

    template < typename T >
    struct statify {

    typedef T value_type;
    typedef int ( T::* pmf_type ) ( int );

    private:

    // helper struct:
    struct func_object {

    value_type object;
    pmf_type func;

    func_object ( value_type const & o, pmf_type f )
    : object ( o )
    , func ( f )
    {}

    };

    // static data:
    static std::auto_ptr< func_object > fo_ptr;

    // this is a monostate class:
    statify ( void );
    statify ( statify const & );
    statify& operator= ( statify const & );
    ~statify ( void ) {}

    public:

    static
    void initialize ( value_type const & t, pmf_type f )
    {
    fo_ptr = std::auto_ptr< func_object >( new func_object( t, f ) );
    }

    static
    int forward ( int i ) {
    if ( fo_ptr.get() == 0 ) {
    throw( std::logic_error( "calling empty function object.\n" ) );
    } else {
    return( ((fo_ptr->object).*(fo_ptr->func))( i ) );
    }
    }

    }; // statify

    template < typename T >
    std::auto_ptr< typename statify<T>::func_object > statify<T>::fo_ptr;



    typedef int ( * int_to_int ) ( int );


    // this is the API that uses a function pointer:
    void print_exec ( int_to_int f, int i ) {
    std::cout << i << " --> " << f(i) << '\n';
    }


    // here is our class with suitable member function:
    struct xxx {

    int factor;

    xxx ( int f )
    : factor ( f )
    {}

    int mult ( int i ) {
    return( factor*i );
    }

    };

    int main ( void ) {
    xxx M ( 5 );
    statify< xxx>::initialize ( M, &xxx::mult );
    print_exec( statify<xxx>::forward, 4 );
    }




    Best

    Kai-Uwe Bux

    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Kai-Uwe Bux, Oct 23, 2005
    #6
  7. Enquiries, Hopkins Research

    Carl Barron Guest

    In article <BF7F43BA.8F32%>, Enquiries,
    Hopkins Research <> wrote:

    > Hi all
    >
    > I have a conundrum that is puzzling me.
    >
    > I have a large codebase in C that I am converting to C++ as fast as possible
    > (i.e. slowly because I keep learning new idioms and stumbling with C++
    > 'features'). One part of the C code is some optimisation functions that
    > expect a pointer to a function which is sent an array of doubles and returns
    > a double i.e. simplified..
    >
    > void optimise( double (*funk)( double* ) );
    >
    > I now have a bunch of classes with member functions which also take double*
    > and return double that I want to use in this optimiser, but the compiler
    > won't let me because:
    >
    > error: argument of type 'double (namespace::class::)(double*)' does not
    > match 'double (*)(double*)'
    >
    > OK - I hadn't thought about that but felt there must be an easy answer.
    > However, I have tried declaring the functions in question as friends (but
    > the class members that the functions use are no longer available) and
    > sending 'pointers' to them a la BS TCPPPL p.419:
    >
    > typedef double (class::*Pstd_mem)( double* pv );
    > Pstd_mem p = &class::eek:pt_ll;
    >
    > ..but nothing I have tried so far works and I am running out of ideas. Can
    > any C++ gurus out there suggest a solution (that is hopefully reliable and
    > efficient)?
    >
    > TIA and please CC replies here
    >
    > Michael
    >

    boost [www.boost.org] has a function wrapper that wraps function
    pointers, functors, and member function calls.

    boost::function<double(double)> is a class that should be a drop in
    replacement for double(*)(double). It is slower than raw function
    pointers but solves your problem and others.

    you have optimize(double (*f)(double))

    change the prototype and functioin definition to

    optimize(boost::function<double(double)> f). Then it should work.

    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Carl Barron, Oct 23, 2005
    #7
  8. Ismail Pazarbasi wrote:
    > If I got it correct, you did this:
    >
    > class SomeClass
    > {
    > public:
    >
    > double OptimizeCallback(double*) { /* ... */ }
    > };
    >
    > typedef double (SomeClass::*Pstd_mem)( double* pv );
    >
    > // somewhere in the code
    > Pstd_mem p = &SomeClass::OptimizeCallback;
    > optimise(p);
    >
    > As previous 3 posters replied, there is a distinction between a
    > non-member function and a member function. The distinction is that
    > latter one needs an additional "this" pointer (something like, "mov
    > ecx, this", in x86 assembly).


    It would be more accurate to say that you need an object to call a
    member function, so you still need an object to call a member function
    through a pointer.

    > In C++, there is no (standard and
    > reliable) way to know, at compile time, where the function is going to
    > be located.


    This is irrelevant and half wrong. The linker knows where in the
    executable the function is located at compile time (and that's all you
    need), but of course the exact location in memory is not known until
    run-time.

    > Valentin's answers are cool. I'm not keen with libraries, and I didn't
    > know whether boost has such a thing. But in that case, you need to use
    > boost, and probably you'll need to ship boost libary (.so or .dll)
    > along with your binary.


    Depends on what part of boost you are using. Particularily,
    boost::function, boost::iterator and boost::bind only need headers.

    > There ways, arguably efficient and reliable, but they are compiler and
    > platform dependent. If you don't have a portability concern, I think we
    > can solve this problem. But again, these ways are not supported by
    > standard, so generated executable may not run properly, next time you
    > compile it with newer version of your current compiler.
    >
    > What I thought, for example, is first defining an "interface", which
    > could be thought as a "struct of function pointers" in C, derive
    > classes from this interface, write a template adapter class that
    > returns pointer to the member function (forcibly and tricky, through
    > vtable offset), pass this pointer to optimise() as if it is the double
    > (funk*)(double*). Since standard doesn't define vtable layout, the code
    > won't be portable, and it may need some more tailoring, if your classes
    > have different inheritance model (multiple, virtual, etc). As Valentin
    > pointed out, this may become difficult to implement for more complex
    > scenarios. Again, I want to point out that I am not really sure how
    > safe it is! Test good and ask your compiler vendor, if you intend to
    > use this:


    <snip weird non-standard code>

    This is illegal in C++ and is not even a behavior you can generally
    count on. Please post standard and valid code only. Thounsands of
    people read this newsgroup (hopefully) expecting the advices given to
    be reliable.


    Jonathan


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Jonathan Mcdougall, Oct 24, 2005
    #8
  9. Jonathan Mcdougall wrote:

    >> Ismail Pazarbasi wrote:
    >>

    >
    >>>>If I got it correct, you did this:
    >>>>
    >>>>class SomeClass
    >>>>{
    >>>>public:
    >>>>
    >>>> double OptimizeCallback(double*) { /* ... */ }
    >>>>};
    >>>>
    >>>>typedef double (SomeClass::*Pstd_mem)( double* pv );
    >>>>
    >>>>// somewhere in the code
    >>>>Pstd_mem p = &SomeClass::OptimizeCallback;
    >>>>optimise(p);
    >>>>
    >>>>As previous 3 posters replied, there is a distinction between a
    >>>>non-member function and a member function. The distinction is that
    >>>>latter one needs an additional "this" pointer (something like, "mov
    >>>>ecx, this", in x86 assembly).

    >
    >>
    >>
    >> It would be more accurate to say that you need an object to call a
    >> member function, so you still need an object to call a member function
    >> through a pointer.
    >>
    >>

    >
    >>>>In C++, there is no (standard and
    >>>>reliable) way to know, at compile time, where the function is going to
    >>>>be located.

    >
    >>
    >>
    >> This is irrelevant and half wrong. The linker knows where in the
    >> executable the function is located at compile time (and that's all you
    >> need), but of course the exact location in memory is not known until
    >> run-time.



    In the presence of virtual functions, the specific function
    that would be called can vary at runtime. (It's possible
    for a compiler to generate additional functions that wrap
    this dispatch, in which case the linker would know, but a
    different level of indirection is added.)

    -- James

    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    James Dennett, Oct 24, 2005
    #9
  10. James Dennett wrote:
    > Jonathan Mcdougall wrote:
    > >> Ismail Pazarbasi wrote:
    > >>>>
    > >>>>In C++, there is no (standard and
    > >>>>reliable) way to know, at compile time, where the function is going to
    > >>>>be located.
    > >>
    > >> This is irrelevant and half wrong. The linker knows where in the
    > >> executable the function is located at compile time (and that's all you
    > >> need), but of course the exact location in memory is not known until
    > >> run-time.

    >
    > In the presence of virtual functions, the specific function
    > that would be called can vary at runtime. (It's possible
    > for a compiler to generate additional functions that wrap
    > this dispatch, in which case the linker would know, but a
    > different level of indirection is added.)


    Yes, but the location of virtual functions in the object file is still
    known at compile-time. What makes them "virtual" is that a pointer
    contains the address of a function and that the contained value may
    change at run-time. This is only a second level of indirection.


    Jonathan


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Jonathan Mcdougall, Oct 25, 2005
    #10
  11. On 26/10/05 14:19, in article djmam7$b9c$,
    "Kai-Uwe Bux" <> wrote:

    > Enquiries, Hopkins Research wrote:
    >
    >>>>

    > [snip]
    >>
    >> I have two efficiency-related questions:
    >>
    >> 1) What is the overhead of using the statify<T>::forward function? It
    >> doesn't appear to be significant in use but I am interested in the
    >> theoretical behaviour.

    >
    >
    > static
    > int forward ( int i ) {
    > if ( fo_ptr.get() == 0 ) {
    > throw( std::logic_error( "calling empty function object.\n" ) );
    > } else {
    > return( ((fo_ptr->object).*(fo_ptr->func))( i ) );
    > }
    > }
    >
    > The overhead lies in the check for fo_ptr to be non-empty. Also, there is
    > some amount of indirection through the v-table of the object. But as soon
    > as the function does anything non-trivial, the run-time of the member
    > function should dominate the whole thing.
    >
    >
    >> 2) I believe that some hidden object copying goes on to make this work
    >> because I had to change the non-copyable status of a large data member
    >> within the class whose member function I am calling to allow it to
    >> compile. Is this just during initialisation or every time the function is
    >> called?

    >
    > No. The copy is done in
    >
    > static
    > void initialize ( value_type const & t, pmf_type f )
    > {
    > fo_ptr = std::auto_ptr< func_object >( new func_object( t, f ) );
    > }
    >
    > Individual calls do not get their own copy.
    >
    > Also, here is a slightly changes version that does not copy at all but just
    > stores a pointer to the object. Beware that I took out some const
    > qualifiers so that it works with non-const member functions, too. Also, in
    > this case the object needs to stay alive to handle all calls. So, you
    > cannot initialize this from a temporary (which should not compile since I
    > took out the const-qualifiers).
    >
    >
    > // pmf_to_static.cc
    > // ================
    >
    > #include <iostream>
    > #include <memory>
    > #include <stdexcept>
    >
    > template < typename T >
    > struct statify {
    >
    > typedef T value_type;
    > typedef int ( T::* pmf_type ) ( int );
    >
    > private:
    >
    > // helper struct:
    > struct func_object {
    >
    > value_type* object;
    > pmf_type func;
    >
    > func_object ( value_type & o, pmf_type f )
    > : object ( &o )
    > , func ( f )
    > {}
    >
    > };
    >
    > // static data:
    > static std::auto_ptr< func_object > fo_ptr;
    >
    > // this is a monostate class:
    > statify ( void );
    > statify ( statify const & );
    > statify& operator= ( statify const & );
    > ~statify ( void ) {}
    >
    > public:
    >
    > static
    > void initialize ( value_type & t, pmf_type f )
    > {
    > fo_ptr = std::auto_ptr< func_object >( new func_object( t, f ) );
    > }
    >
    > static
    > int forward ( int i ) {
    > if ( fo_ptr.get() == 0 ) {
    > throw( std::logic_error( "calling empty function object.\n" ) );
    > } else {
    > return( ((*(fo_ptr->object)).*(fo_ptr->func))( i ) );
    > }
    > }
    >
    > }; // statify
    >
    > template < typename T >
    > std::auto_ptr< typename statify<T>::func_object > statify<T>::fo_ptr;
    >
    >
    >
    > typedef int ( * int_to_int ) ( int );
    >
    > void print_exec ( int_to_int f, int i ) {
    > std::cout << i << " --> " << f(i) << '\n';
    > }
    >
    >
    > struct xxx {
    >
    > int factor;
    >
    > xxx ( int f )
    > : factor ( f )
    > {}
    >
    > int mult ( int i ) {
    > return( factor*i );
    > }
    >
    > };
    >
    > int main ( void ) {
    > xxx M ( 5 );
    > statify< xxx>::initialize ( M, &xxx::mult );
    > print_exec( statify<xxx>::forward, 4 );
    > statify<xxx>::initialize( xxx(6), &xxx::mult ); // should be an error!!
    > }
    >
    >
    >
    > Best
    >
    > Kai-Uwe Bux
    >


    Thanks again Kai-Uwe - this works well and allows me to go back to
    non-copyable objects.

    Michael


    _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

    _/ _/ _/_/_/ Hopkins Research Ltd
    _/ _/ _/ _/
    _/_/_/_/ _/_/_/ http://www.hopkins-research.com/
    _/ _/ _/ _/
    _/ _/ _/ _/ 'touch the future'

    _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    Michael Hopkins, Oct 27, 2005
    #11
  12. I have already stated this is "not a good nor a standard way".

    My intention was making no changes on existing code, not even
    overloading optimize, and providing a way to pass various objects to
    optimize function through the adapter. I thought using static methods
    may introduce locking, if this is a multithreaded application and I
    thought using vtable would be better in this case. May be I was wrong,
    because never tested or thought long enough to make a final decision,
    this was just a solution for my current environment. Nevertheless,
    since standard doesn't specify vtable layout, which means it depends on
    implementation, I have stated, many times, that the code may not run
    even with the next version of the same compiler.

    Ismail


    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.moderated. First time posters: Do this! ]
    Ismail Pazarbasi, Oct 29, 2005
    #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. Newsgroup - Ann
    Replies:
    5
    Views:
    594
    John Carson
    Jul 30, 2003
  2. Fraser Ross
    Replies:
    4
    Views:
    1,028
    Fraser Ross
    Aug 14, 2004
  3. Stephen Howe
    Replies:
    2
    Views:
    282
    Stephen Howe
    Nov 6, 2012
  4. somenath
    Replies:
    10
    Views:
    265
    James Kanze
    Jul 2, 2013
  5. somenath
    Replies:
    2
    Views:
    149
    somenath
    Aug 29, 2013
Loading...

Share This Page