Member and static functions while assignment

A

Alex Vinokur

I have the following problem.

class Base
{
public:
void (*pfunc) (int) = 0;
};

class Derived : public Base
{
public:
void (*pfunc) (int a)
{
// Stuff
}
};


class Foo
{
private:
void (*pf) (int);
public:
Foo (Base* ptr)
{
pf = ptr->pfunc; // Error, because pfunc is a member function,
not static
}
};

Is there any way to do something like "pf = ptr->pfunc"?


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
M

mlimber

Alex said:
I have the following problem.

class Base
{
public:
void (*pfunc) (int) = 0;

This line won't compile. It's neither a static integral constant nor a
pure virtual function, but you seem to have mixed the syntax for the
two.
};

class Derived : public Base
{
public:
void (*pfunc) (int a)

You can't define a body for a pointer to a function. Please see the FAQ
for this group on how to post code:

http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8
{
// Stuff
}
};


class Foo
{
private:
void (*pf) (int);
public:
Foo (Base* ptr)
{
pf = ptr->pfunc; // Error, because pfunc is a member function,
not static

You have a lot bigger problems than that!
}
};

Is there any way to do something like "pf = ptr->pfunc"?

Yes. See the FAQs:

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

Cheers! --M
 
V

Victor Bazarov

Alex said:
I have the following problem.

class Base
{
public:
void (*pfunc) (int) = 0;

A pointer to a function taking an int and returning void.
};

class Derived : public Base
{
public:
void (*pfunc) (int a)

Huh? Another pointer to a function...
{
// Stuff

Are you trying to define a body after declaring a pointer to a function?
}
};


class Foo
{
private:
void (*pf) (int);

OK, a pointer to a function.
public:
Foo (Base* ptr)
{
pf = ptr->pfunc; // Error, because pfunc is a member function,
not static
}
};

Is there any way to do something like "pf = ptr->pfunc"?

What are you trying to accomplish here? Perhaps read about the template
'std::binder_1st', you can do something like

pf = std::bind1st(&Base::pfunc, ptr);

although it is a bit convoluted, but should get you what you want, IIUYC.

Next time try to show what you intend to do with 'pf'.

V
 
A

Alex Vinokur

mlimber said:
This line won't compile. It's neither a static integral constant nor a
pure virtual function, but you seem to have mixed the syntax for the
two.
[snip]

My first message was unlucky. Please ignore it.

Here is problematic program.
====== foo1.cpp ======
struct Base
{
virtual void func (int) = 0;
};

struct Derived : public Base
{
void func (int)
{
// Stuff
}
};

struct Foo
{
void (*pfunc) (int);
Base* p_;

Foo (Base* p) : p_ (p) {}

void doit ()
{

// Here is what I want to reach
pfunc = p_->func;

// ------------------------
// g++ 4.0.1 produces the following error message:
// ........................
// error: argument of type 'void (Base::)(int)'
// does not match 'void (*)(int)
// ........................
// because func() is _member_ (not static) function
// ------------------------
}
};


int main ()
{
Base* p = new Derived;
Foo foo (p);
delete p;

return 0;
}
======================


Here is a _partial_ solution of the problem.
====== foo2.cpp ======
struct Base
{
virtual void func (int) = 0;
};

struct Derived : public Base
{
void func (int)
{
// Stuff
}
};

struct Foo
{
void (*pfunc) (int);
static Base* p_s;

Foo (Base* p) { p_s = p; }

static void wrapper(int a)
{
p_s->func (a);
}

void doit ()
{
pfunc = wrapper;
}
};
Base* Foo::p_s = 0;


int main ()
{
Base* p = new Derived;
Foo foo (p);
delete p;

return 0;
}

======================
 
V

Victor Bazarov

Alex said:
This line won't compile. It's neither a static integral constant nor a
pure virtual function, but you seem to have mixed the syntax for the
two.

[snip]

My first message was unlucky. Please ignore it.

Here is problematic program.
====== foo1.cpp ======
struct Base
{
virtual void func (int) = 0;

Add:

virtual ~Base() {}
};

struct Derived : public Base
{
void func (int)
{
// Stuff
}
};

struct Foo
{
void (*pfunc) (int);
Base* p_;

Foo (Base* p) : p_ (p) {}

void doit ()
{

// Here is what I want to reach
pfunc = p_->func;

And then what? How do you intend to use 'pfunc'?
// ------------------------
// g++ 4.0.1 produces the following error message:
// ........................
// error: argument of type 'void (Base::)(int)'
// does not match 'void (*)(int)
// ........................
// because func() is _member_ (not static) function
// ------------------------
}
};


int main ()
{
Base* p = new Derived;
Foo foo (p);
delete p;

return 0;
}
======================


Here is a _partial_ solution of the problem.

Which problem?
====== foo2.cpp ======
struct Base
{
virtual void func (int) = 0;
};

struct Derived : public Base
{
void func (int)
{
// Stuff
}
};

struct Foo
{
void (*pfunc) (int);
static Base* p_s;

Foo (Base* p) { p_s = p; }

static void wrapper(int a)
{
p_s->func (a);
}

void doit ()
{
pfunc = wrapper;
}
};
Base* Foo::p_s = 0;


int main ()
{
Base* p = new Derived;
Foo foo (p);
delete p;

return 0;
}

======================

Study this:

////////////////////////////////////
struct Base
{
virtual void func (int) = 0;
virtual ~Base() {}
};

struct Derived : public Base
{
void func(int)
{
// Stuff
}
};

struct Foo
{
void (Base::*pfunc) (int);

Foo (void (Base::*pf) (int)) : pfunc(pf) {}

void doit(Base* p_)
{
(p_->*pfunc)(42);
}
};


int main ()
{
Base* p = new Derived;
Foo foo(&Base::func);

foo.doit(p);

delete p;
}
/////////////////////////////////////////

V
 
M

mlimber

Alex said:
My first message was unlucky. Please ignore it.

Here is problematic program.
====== foo1.cpp ======
struct Base
{
virtual void func (int) = 0;
};

struct Derived : public Base
{
void func (int)
{
// Stuff
}
};

struct Foo
{
void (*pfunc) (int);
Base* p_;

Foo (Base* p) : p_ (p) {}

void doit ()
{

// Here is what I want to reach
pfunc = p_->func;

// ------------------------
// g++ 4.0.1 produces the following error message:
// ........................
// error: argument of type 'void (Base::)(int)'
// does not match 'void (*)(int)
// ........................
// because func() is _member_ (not static) function
// ------------------------
}
};

Ok, now you've posed the problem correctly, and in order to find the
solution, all you need to do is read the FAQs to which I previously
referred you:

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

[snip]
Here is a _partial_ solution of the problem.
====== foo2.cpp ======
struct Base
{
virtual void func (int) = 0;
};

struct Derived : public Base
{
void func (int)
{
// Stuff
}
};

struct Foo
{
void (*pfunc) (int);
static Base* p_s;

Foo (Base* p) { p_s = p; }

static void wrapper(int a)
{
p_s->func (a);
}

void doit ()
{
pfunc = wrapper;
}
};
Base* Foo::p_s = 0;


int main ()
{
Base* p = new Derived;
Foo foo (p);
delete p;

return 0;
}

This is not a good solution. It is not necessary to resort to static
members and methods. See the FAQs.

Cheers! --M
 
A

Alex Vinokur

Victor Bazarov wrote:
[snip]
Study this:

////////////////////////////////////
struct Base
{
virtual void func (int) = 0;
virtual ~Base() {}
};

struct Derived : public Base
{
void func(int)
{
// Stuff
}
};

struct Foo
{ ---------------------------------
void (Base::*pfunc) (int);
But here I have to use
void (*pfunc) (int);
---------------------------------
Foo (void (Base::*pf) (int)) : pfunc(pf) {}

void doit(Base* p_)
{
(p_->*pfunc)(42);
}
};


int main ()
{
Base* p = new Derived;
Foo foo(&Base::func);

foo.doit(p);

delete p;
}
/////////////////////////////////////////

V


Alex Vinokur
 
A

Alf P. Steinbach

* Alex Vinokur:
I have to use
void (*pfunc) (int);

[to call a member function]

If you have any leeway at all, consider using a functor object instead. That
can encapsulate an ordinary static function, or a member function bound to an
object (sometimes called a _closure_ or a _delegate_), or whatever. See the
FAQ items at the end of the FAQ page that "mlimber" pointed to.
 
A

Alex Vinokur

Alf said:
* Alex Vinokur:
I have to use
void (*pfunc) (int);

[to call a member function]

If you have any leeway at all, consider using a functor object instead. That
can encapsulate an ordinary static function, or a member function bound to an
object (sometimes called a _closure_ or a _delegate_), or whatever. See the
FAQ items at the end of the FAQ page that "mlimber" pointed to.
[snip]

Thanks.

I saw the FAQ.

But it seems that it doesn't solve my problem.


Here my situation.

struct BaseBar
{
// Stuff: Data members
virtual void callback (int) = 0;
virtual ~BaseBar() {}
};

struct Bar1 : public BaseBar
{
// Stuff: Data members
void callback (int)
{
// Stuff
}
};


struct Bar2 : public BaseBar
{
// Stuff: Data members
void callback (int)
{
// Stuff
}
};

struct Config
{
// Stuff: Data members
void (*the_callback) (int); // We can't change this prototype

};

struct Foo
{
// Stuff: Data members
Config config_;
Foo (BaseBar* ptr_i)
{
// Stuff
// Here I have to do what is impossible to do:
// -----------------------
// config_.the_callback = ptr_i->callback;
// -----------------------
}
};

int main ()
{
Bar1 bar1;
Bar2 bar2;

Foo foo1 (&bar1);
Foo foo2 (&bar2);
Foo foo3 (&bar1);

return 0;
}


The approach from
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
doesn't help here because we have several Bar-ojects created.


Alex Vinokur
 
A

Alf P. Steinbach

* Alex Vinokur:
void (*the_callback) (int); // We can't change this prototype


The approach from
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
doesn't help here because we have several Bar-ojects created.

If the callback is only called during initialization I don't see why not.

Otherwise, if you can specify the int argument to the callback, then use a
std::map as the global, not just a single pointer, and the int argument as key
to the map.

Otherwise, if you can't specify the argument then it seems the API you're
using supports only a single callback which can be called at any time, and you
then have to decide whether you want just a single object to receive the call
or whether to distribute it to all objects, or what.
 
A

Alex Vinokur

Alf said:
* Alex Vinokur:

If the callback is only called during initialization I don't see why not.

Otherwise, if you can specify the int argument to the callback, then use a
std::map as the global, not just a single pointer, and the int argument as key
to the map.


I tried to do something like this.

struct BaseBar
{
// Stuff: Data members
virtual void callback (int) = 0;
virtual ~BaseBar() {}
};


struct Bar1 : public BaseBar
{
// Stuff: Data members
void callback (int)
{
// Stuff
}
};


struct Bar2 : public BaseBar
{
// Stuff: Data members
void callback (int)
{
// Stuff
}
};


struct Config
{
// Stuff: Data members
void (*the_callback) (int); // We can't change this prototype
};


struct Foo
{
static int id_counter_s;
static map<int, BaseBar*> p_bar_s;
const int id_;

Config config_;

static foo_callback (int x)
{
p_bar_s[id_ /* id_ is member; so it is illegal */]->callback (x);

}

Foo (BaseBar* ptr_i) : id_ (id_counter_s)
{
p_bar_s[id_] = ptr_i;

// Stuff
config_.the_callback = foo_callback;
}
};
int Foo::id_counter_s = 0;
map<int, BaseBar*> Foo::p_bar_s;


int main ()
{
Bar1 bar1;
Bar2 bar2;

Foo foo1 (&bar1);
Foo foo2 (&bar2);
Foo foo3 (&bar1);


return 0;



}

Otherwise, if you can't specify the argument then it seems the API you're
using supports only a single callback which can be called at any time, and you
then have to decide whether you want just a single object to receive the call
or whether to distribute it to all objects, or what.


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
A

Alex Vinokur

Alex Vinokur said:
* Alex Vinokur:

If the callback is only called during initialization I don't see why not.

Otherwise, if you can specify the int argument to the callback, then use a
std::map as the global, not just a single pointer, and the int argument as key
to the map.


I tried to do something like this. [snip]
Otherwise, if you can't specify the argument then it seems the API you're
using supports only a single callback which can be called at any time, and you
then have to decide whether you want just a single object to receive the call
or whether to distribute it to all objects, or what.
[snip]

I have resolved the problem in my _specific_ conditions.

Here is an erroneous program that doesn't take into account any _specific_ conditions.

------ erroneous program ------
struct BaseCaller
{
virtual void callback (long) = 0;
virtual ~BaseCaller() {}
};


struct Caller1 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Caller2 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Worker
{
void (*the_callback) (long); // We can't change this prototype
};


#define RED 1
#define BLUE 2
#define GREEN 3

struct Called
{
const int type_; // RED, BLUE or GREEN
Worker Worker_;
Called (int type_i, BaseCaller* ptr_i) : type_ (type_i)
{
Worker_.the_callback = ptr_i->callback; // Erroneous
}
};


int main ()
{
Caller1 caller1;
Caller2 caller2;

Called called1 (RED, &caller1);
Called called2 (BLUE, &caller2);
Called called3 (GREEN, &caller1);

return 0;
}
-------------------------------


Here are _specific_ conditions:
1. Maximum three types of Called-object can exist simultaneously.
2. No type of Called-object (RED, BLUE, GREEN) can exist more than once.

Here is a valid program.
------ valid program ------

#include <cassert>
#include <map>
using namespace std;

struct BaseCaller
{
virtual void callback (long) = 0;
virtual ~BaseCaller() {}
};


struct Caller1 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Caller2 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Worker
{
void (*the_callback) (long); // We can't change this prototype
};


#define RED 1
#define BLUE 2
#define GREEN 3

struct Called
{
static map<int, BaseCaller*> types_s;
const int type_; // RED, BLUE or GREEN
Worker Worker_;

static void red_callback_s (long arg_i)
{
types_s[RED]->callback(arg_i);
}

static void blue_callback_s (long arg_i)
{
types_s[BLUE]->callback(arg_i);
}

static void green_callback_s (long arg_i)
{
types_s[GREEN]->callback(arg_i);
}

Called (int type_i, BaseCaller* ptr_i) : type_ (type_i)
{
assert (types_s.count(type_) == 0); // In actual program to be replaced by some check
types_s[type_] = ptr_i;

switch (type_)
{
case RED:
Worker_.the_callback = red_callback_s;
break;

case BLUE:
Worker_.the_callback = blue_callback_s;
break;

case GREEN:
Worker_.the_callback = green_callback_s;
break;

default:
assert(0);
break;
}

}

};
map<int, BaseCaller*> Called::types_s;


int main ()
{
Caller1 caller1;
Caller2 caller2;

Called called1 (RED, &caller1);
Called called2 (BLUE, &caller2);
Called called3 (GREEN, &caller1);

return 0;
}
 
A

Alex Vinokur

Alex Vinokur wrote:

[snip]
Here is a valid program.
------ valid program ------
[snip]

struct Called
{ [snip]

Called (int type_i, BaseCaller* ptr_i) : type_ (type_i)
{
assert (types_s.count(type_) == 0); // In actual program to be replaced by some check
types_s[type_] = ptr_i;

switch (type_)
{
case RED:
Worker_.the_callback = red_callback_s;
break;

case BLUE:
Worker_.the_callback = blue_callback_s;
break;

case GREEN:
Worker_.the_callback = green_callback_s;
break;

default:
assert(0);
break;
}
}

~Called
{
types_s.erase(type_);
}
[snip]

Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
A

Aleksey Loginov

Alex said:
Here are _specific_ conditions:
1. Maximum three types of Called-object can exist simultaneously.
2. No type of Called-object (RED, BLUE, GREEN) can exist more than once.

Here is a valid program.
------ valid program ------

#include <cassert>
#include <map>
using namespace std;

struct BaseCaller
{
virtual void callback (long) = 0;
virtual ~BaseCaller() {}
};


struct Caller1 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Caller2 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Worker
{
void (*the_callback) (long); // We can't change this prototype
};


#define RED 1
#define BLUE 2
#define GREEN 3

struct Called
{
static map<int, BaseCaller*> types_s;
const int type_; // RED, BLUE or GREEN
Worker Worker_;

static void red_callback_s (long arg_i)
{
types_s[RED]->callback(arg_i);
}

static void blue_callback_s (long arg_i)
{
types_s[BLUE]->callback(arg_i);
}

static void green_callback_s (long arg_i)
{
types_s[GREEN]->callback(arg_i);
}

Called (int type_i, BaseCaller* ptr_i) : type_ (type_i)
{
assert (types_s.count(type_) == 0); // In actual program to be replaced by some check
types_s[type_] = ptr_i;

switch (type_)
{
case RED:
Worker_.the_callback = red_callback_s;
break;

case BLUE:
Worker_.the_callback = blue_callback_s;
break;

case GREEN:
Worker_.the_callback = green_callback_s;
break;

default:
assert(0);
break;
}

}

};
map<int, BaseCaller*> Called::types_s;


int main ()
{
Caller1 caller1;
Caller2 caller2;

Called called1 (RED, &caller1);
Called called2 (BLUE, &caller2);
Called called3 (GREEN, &caller1);

return 0;
}


#include <algorithm>
#include <iostream>

struct BaseCaller
{
virtual void callback (long) = 0;
virtual ~BaseCaller() {}
};


struct Caller1 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Caller2 : public BaseCaller
{
void callback (long)
{
// Stuff
}
};


struct Worker
{
void (*the_callback) (long); // We can't change this prototype
};

enum types { red, blue, green };

template<types id>
struct CallerWrapper
{
CallerWrapper ( BaseCaller * ptr_i ) {
CallerWrapper<id>::instance (ptr_i); }

static BaseCaller * instance ( BaseCaller * ptr_i ) {
static BaseCaller * ptr_s = 0;

BaseCaller * tmp = ptr_s; ptr_s = ptr_i;
return tmp;
}

static BaseCaller * instance ( ) {
BaseCaller * tmp = CallerWrapper<id>::instance (0);
CallerWrapper<id>::instance (tmp);
return tmp;
}

static const types type = id;
static void callback ( long arg_i ) {
CallerWrapper<id>::instance ()->callback (arg_i); }

};

struct Called
{
const types type_; // RED, BLUE or GREEN
Worker Worker_;

template< typename Singleton >
Called ( Singleton const & ) : type_ (Singleton::type) {
Worker_.the_callback = Singleton::callback; }

};


int main ()
{
Caller1 caller1;
Caller2 caller2;


Called called1 (CallerWrapper<red>(&caller1));
Called called2 (CallerWrapper<blue>(&caller2));
Called called3 (CallerWrapper<green>(&caller1));


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,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top