a manipulator wrapped inside a struct/class does not compile

S

stoptv

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;
}
 
V

Victor Bazarov

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
 
S

stoptv

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!
 
V

Victor Bazarov

why is that exactly?

Why is what exactly? I made two statements, which one are you asking about?
'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
 
J

John Harrison

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
 
A

Andrej Hristoliubov

Victor said:
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.


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.


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.
 
S

stoptv

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..
 
J

John Harrison

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




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




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
 
S

STOP

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;
}
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top