a manipulator wrapped inside a struct/class does not compile

Discussion in 'C++' started by stoptv@gmail.com, Oct 28, 2005.

  1. Guest

    Hello group, this is my dilemma:
    ------------------------------------------------------------------------

    #include <iostream>

    using namespace std;

    // a regular manipulator
    ostream & hello( ostream & os ) { return os << "regular: hello"; }

    struct Test // a manipulator wrapped inside a struct
    {
    ostream & hello( ostream & os ) { return os << "wrapped: hello"; }
    };

    int main( )
    {
    cout << hello << endl; // this works just fine..

    Test t;
    cout << t.hello << endl; // and this doesn't compile! WHY??

    /* note: gcc 2.95.4 says there's no matching function to call,
    * and then lists the possible applicators; but there it is:
    *
    * class ostream & ostream::eek:perator <<(ostream & (*)(ostream &))
    *
    * isn't that the wrapped manipulator's signature?
    * I don't get it. Would anyone be so kind to explain? thanks!
    */

    return 0;
    }
    , Oct 28, 2005
    #1
    1. Advertising

  2. wrote:
    > Hello group, this is my dilemma:
    > ------------------------------------------------------------------------
    >
    > #include <iostream>
    >
    > using namespace std;
    >
    > // a regular manipulator
    > ostream & hello( ostream & os ) { return os << "regular: hello"; }
    >
    > struct Test // a manipulator wrapped inside a struct
    > {
    > ostream & hello( ostream & os ) { return os << "wrapped: hello"; }


    A pointer to a function and a pointer to a member function are not
    compatible. A manipulator is expected to be a pointer to a function,
    not to a member.

    > };
    >
    > int main( )
    > {
    > cout << hello << endl; // this works just fine..
    >
    > Test t;
    > cout << t.hello << endl; // and this doesn't compile! WHY??


    Because 't.hello' is a syntax error. You either need 't.hello()' or
    '&Test::hello', to make something of 'hello'. And the second one is not
    going to fly due to pointer incompatibility I mentioned above. And the
    first one is not what you want.

    > /* note: gcc 2.95.4 says there's no matching function to call,
    > * and then lists the possible applicators; but there it is:
    > *
    > * class ostream & ostream::eek:perator <<(ostream & (*)(ostream &))
    > *
    > * isn't that the wrapped manipulator's signature?
    > * I don't get it. Would anyone be so kind to explain? thanks!
    > */
    >
    > return 0;
    > }
    >


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

  3. Guest

    > A pointer to a function and a pointer to a member function are not
    > compatible. A manipulator is expected to be a pointer to a function,
    > not to a member.


    why is that exactly?

    >Because 't.hello' is a syntax error. You either need 't.hello()' or
    >'&Test::hello', to make something of 'hello'. And the second one is not
    >going to fly due to pointer incompatibility I mentioned above. And the
    >first one is not what you want.


    't.hello()' wouldn't work because the applicator expects a pointer -
    not a method.

    '&Test::hello' is a pointer to a class method. That's not what I need.
    I have an instance method 'hello'.

    I can see 't.hello' is a syntax error, but am curious why this is so.
    As far as I can see the compiler is reacting as though 'hello' is of
    type 'ostream& (Test::*)( ostream& )', but the 'Test::' part is
    irrelevant.. I have dereferenced it with a dot after 't' as in:

    struct Test
    {
    int whatever;
    } t;

    't.whatever' is of type 'int', not 'Test::int'!
    So why isn't 't.hello' of type 'ostream&(*)(ostream&)'? Or even
    better.. I believe you understand what kind of use I am aiming at.. is
    there a way to circumvent this problem?

    Thanks!
    , Oct 28, 2005
    #3
  4. wrote:
    >>A pointer to a function and a pointer to a member function are not
    >>compatible. A manipulator is expected to be a pointer to a function,
    >>not to a member.

    >
    >
    > why is that exactly?


    Why is what exactly? I made two statements, which one are you asking about?

    >>Because 't.hello' is a syntax error. You either need 't.hello()' or
    >>'&Test::hello', to make something of 'hello'. And the second one is not
    >>going to fly due to pointer incompatibility I mentioned above. And the
    >>first one is not what you want.

    >
    >
    > 't.hello()' wouldn't work because the applicator expects a pointer -
    > not a method.


    You can make 'hello' actually return a pointer.

    > '&Test::hello' is a pointer to a class method. That's not what I need.
    > I have an instance method 'hello'.


    The term is "non-static member function". Perhaps you should start using
    it...

    > I can see 't.hello' is a syntax error, but am curious why this is so.


    Because the language was designed that way.

    > As far as I can see the compiler is reacting as though 'hello' is of
    > type 'ostream& (Test::*)( ostream& )', but the 'Test::' part is
    > irrelevant.. I have dereferenced it with a dot after 't' as in:
    >
    > struct Test
    > {
    > int whatever;
    > } t;
    >
    > 't.whatever' is of type 'int', not 'Test::int'!
    > So why isn't 't.hello' of type 'ostream&(*)(ostream&)'?


    Because. A function name and an object name behave differently when used
    in an expression. You _could_ define 'hello' to be a member of "Test" and
    have a type "a pointer to function":

    struct Test {
    ostream& (*hello)(ostream&);
    };

    which would allow you to use 't.hello' as a stand-alone thing. The value
    of it would be used then. Now, how to assign that pointer a particular
    value, is another question.

    > Or even
    > better.. I believe you understand what kind of use I am aiming at.. is
    > there a way to circumvent this problem?


    See my recommendation above. The trick is still going to be the assignment
    of a particular value to 'hello'.

    V
    Victor Bazarov, Oct 28, 2005
    #4
  5. wrote:
    >>A pointer to a function and a pointer to a member function are not
    >>compatible. A manipulator is expected to be a pointer to a function,
    >>not to a member.

    >
    >
    > why is that exactly?


    Because a member function has special access to one particular object. A
    regular function does not. Of course there is nothing at all to stopyou
    writing a regular function which calls a member function, and then you
    can use the regular function where you wanted to use the member function.

    john
    John Harrison, Oct 28, 2005
    #5
  6. Victor Bazarov wrote:
    > wrote:
    > > Hello group, this is my dilemma:
    > > ------------------------------------------------------------------------
    > >
    > > #include <iostream>
    > >
    > > using namespace std;
    > >
    > > // a regular manipulator
    > > ostream & hello( ostream & os ) { return os << "regular: hello"; }
    > >
    > > struct Test // a manipulator wrapped inside a struct
    > > {
    > > ostream & hello( ostream & os ) { return os << "wrapped: hello"; }

    >
    > A pointer to a function and a pointer to a member function are not
    > compatible. A manipulator is expected to be a pointer to a function,
    > not to a member.
    >
    > > };
    > >
    > > int main( )
    > > {
    > > cout << hello << endl; // this works just fine..
    > >
    > > Test t;
    > > cout << t.hello << endl; // and this doesn't compile! WHY??

    >
    > Because 't.hello' is a syntax error. You either need 't.hello()' or
    > '&Test::hello', to make something of 'hello'. And the second one is not
    > going to fly due to pointer incompatibility I mentioned above. And the
    > first one is not what you want.
    >
    > > /* note: gcc 2.95.4 says there's no matching function to call,
    > > * and then lists the possible applicators; but there it is:
    > > *
    > > * class ostream & ostream::eek:perator <<(ostream & (*)(ostream &))
    > > *
    > > * isn't that the wrapped manipulator's signature?
    > > * I don't get it. Would anyone be so kind to explain? thanks!
    > > */
    > >
    > > return 0;
    > > }
    > >

    >
    > V


    Vitya at his finest!!!

    Do listen to Victor, I neither had seen this in production not
    Victor's code. And I know Victor for quite some time now (Vitya is it
    25 or 30 years in total is the duration of our acquaintance and
    bestfriendship?).


    Pass my birthday wishes to your sister Dinachka.
    Andrej Hristoliubov, Oct 29, 2005
    #6
  7. Guest

    > Why is what exactly? I made two statements, which one are you asking about?

    I meant.. why aren't a pointer to a function and a pointer to a member
    function compatible?

    >The term is "non-static member function". Perhaps you should start using it...


    Perhaps, but English is not my mother tongue so please don't take it
    against me. Besides, we've understood eachother just as fine using
    these different expressions. Fortunately us humans are far more
    flexible than compilers :)

    I've tried using the construct with ostream& (*hello)(ostream&); you
    have proposed

    >Now, how to assign that pointer a particular value, is another question.


    and this turned out to be a rather difficult question! I was unable to
    get a hold of the address of my non-static member function :)

    Dear Victor (and the rest of the group), I have a feeling you are
    keeping some important details to yourself. My question is not an
    academic one, but rather a simple design question, a question of
    ergonomics if you wish. I would really appreciate your help.

    Though discussing language odditys might be fun sometimes, my ultimate
    goal is using the class in expressions like this:

    MyClass instance;

    cout << instance.something << endl;
    cout << instance.somethingElse << endl;

    The semantics I'm looking for is that an applicator runs 'something'
    and 'somethingElse' in the context of an instance. How can I achieve
    this? It doesn't have to be pretty from the inside :)

    Thank you Victor, John and others..
    , Oct 29, 2005
    #7
  8. wrote:
    >>Why is what exactly? I made two statements, which one are you asking about?

    >
    >
    > I meant.. why aren't a pointer to a function and a pointer to a member
    > function compatible?
    >
    >
    >>The term is "non-static member function". Perhaps you should start using it...

    >
    >
    > Perhaps, but English is not my mother tongue so please don't take it
    > against me. Besides, we've understood eachother just as fine using
    > these different expressions. Fortunately us humans are far more
    > flexible than compilers :)
    >
    > I've tried using the construct with ostream& (*hello)(ostream&); you
    > have proposed
    >
    >
    >>Now, how to assign that pointer a particular value, is another question.

    >
    >
    > and this turned out to be a rather difficult question! I was unable to
    > get a hold of the address of my non-static member function :)
    >
    > Dear Victor (and the rest of the group), I have a feeling you are
    > keeping some important details to yourself. My question is not an
    > academic one, but rather a simple design question, a question of
    > ergonomics if you wish. I would really appreciate your help.
    >
    > Though discussing language odditys might be fun sometimes, my ultimate
    > goal is using the class in expressions like this:
    >
    > MyClass instance;
    >
    > cout << instance.something << endl;
    > cout << instance.somethingElse << endl;
    >
    > The semantics I'm looking for is that an applicator runs 'something'
    > and 'somethingElse' in the context of an instance. How can I achieve
    > this? It doesn't have to be pretty from the inside :)
    >
    > Thank you Victor, John and others..
    >


    Well here's your problem, you want the return from instance.something()
    to be a thing that remembers what instance was so that the thing can
    access the context represented by instance.

    Now think about what a function is, it is stateless, it cannot remember
    any context or anything else. So give up on the idea of
    instance.something() returning a function. Instead instance.something()
    must return an object.

    Something like this (untested)

    class MyClass;

    class MyManipulator
    {
    public:
    MyManipulator(MyClass* i) : inst(i) {}
    MyClass* get_inst() const { return inst; }
    private:
    MyClass* inst;
    };

    class MyClass
    {
    public:
    MyManipulator something() { return MyManipulator(this); }
    };

    ostream& operator<<(ostream& os, const MyManipulator& m)
    {
    MyInstance* inst = m.get_inst();
    // do something with inst
    return is;
    }

    MyClass instance;
    cout << instance.something() << endl;

    john
    John Harrison, Oct 29, 2005
    #8
  9. STOP Guest

    Thanks John! Your suggestion pushed me into the right direction. I'll
    be exploiting c++'s typesystem to overload (specialize) the
    'operator<<' applicator. Basically, I've slightly modified your
    solution and generalized it into a template that's simple enough to
    use. I'm posting the final solution in case anyone's interested..
    ---------------------------------------------------------------------------------
    #include <iostream>
    #include <cstdlib>

    using namespace std;

    template<class Outer, class TypesystemHook>
    class Target
    {
    Outer& _outer;
    public:
    Target( Outer& outer ) : _outer( outer ) {}
    Outer& operator()( void ) { return _outer; }
    };

    class MyClass
    {
    public:

    MyClass() : average(*this), sum(*this)
    {
    for( unsigned int i = 0; i < DataSize; i++ ) { _data =
    rand()%20; }
    }

    Target<MyClass, class Average {}> average;
    friend ostream& operator<<( ostream& os, Target<MyClass,Average>& t
    )
    {
    return os << static_cast<double>( t().getSum() ) / DataSize;
    }

    Target<MyClass, class Sum {}> sum;
    friend ostream& operator<<( ostream& os, Target<MyClass,Sum>& t )
    {
    return os << t().getSum();
    }

    private:
    static const unsigned int DataSize = 10;
    int _data[DataSize];

    int getSum() // helper
    {
    int sum = 0;
    for( unsigned int i = 0; i < DataSize; i++ ) { sum += _data;
    }
    return sum;
    }
    };

    int main( int argc, char* argv[] )
    {
    MyClass instance;

    cout << instance.sum << endl;
    cout << instance.average << endl;

    return 0;
    }
    ---------------------------------------------------------------------------------
    Once again, thank you all for your helpfull suggestions and comments,
    John especially!
    STOP, Oct 30, 2005
    #9
    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. rwawryk
    Replies:
    3
    Views:
    360
    Victor Bazarov
    Aug 7, 2003
  2. Marc Schellens

    ostream manipulator class

    Marc Schellens, Nov 19, 2003, in forum: C++
    Replies:
    1
    Views:
    302
    Victor Bazarov
    Nov 19, 2003
  3. Chris Fogelklou
    Replies:
    36
    Views:
    1,335
    Chris Fogelklou
    Apr 20, 2004
  4. Nagaraj
    Replies:
    1
    Views:
    823
    Lionel B
    Mar 1, 2007
  5. Replies:
    3
    Views:
    1,069
Loading...

Share This Page