design woes ... confused on an implementation approach

M

ma740988

Select parameters in a vendors API file is as follows:

#ifdef __cplusplus
typedef void (*VOIDFUNCPTR)(...); /* ptr to function returning void
*/
#else
typedef void (*VOIDFUNCPTR)(); /* ptr to function returning void
*/
#endif /* __cplusplus */

enum CAUSE { CHAN0_COMPLETE, CHAN0_MISS, CHAN0_HIT, CHAN0_ISM };
bool IntConnect( CAUSE c, VOIDFUNCPTR p, int idx, int jdx);
// end vendors file

The member function IntConnect that takes a cause; a VOIDFUNCPTR; and
a two integer variables.

The basic premise: You'll pass your desired - static/global - member
function + cause, etc .. to the vendors IntConnect member function.

To bypass the 'procedural approach' I have a class transfer that takes
a map and a function pointer.

class transfer {
static std::auto_ptr<cb_base> user_cb;
map<CAUSE, VOIDFUNCPTR> myMap;
static void callback_mem_func1(...) {
// call user function passed in via connect_interrupt
cb_base &cb = *user_cb;
}
static void callback_mem_func2(...) {
// call user function passed in via connect_interrupt
cb_base &cb = *user_cb;
}
/// more

public:
transfer() {
myMap[CHAN0_COMPLETE] = &transfer::callback_mem_func1;
myMap[CHAN0_MISS] = &transfer::callback_mem_func2;
// more
}

template <typename T>
bool connect_interrupt(
CAUSE c,
int param1,
int param2,
T& t,
void (T::*f)(...) ) )
{
map<CAUSE, VOIDFUNCPTR>::iterator it = myMap.begin();
for (; it != myMap.end(); ++it)
{
if ( it->first == c )
{
bool success = IntConnect(
(*it).first,
(*it).second,
param1,
param2
);

if ( success ) {
user_cb.reset(new cb_derived<T>(t, f));
}
break;
}
} // end for
};
With this approach I'll register with IntConnect a static member
function. The static member function will - in turn - call user
desired member function.

At issue: The current approach to user_cb WONT work. I need to have
vector or something similar .. This way within the member functions
callback_mem_func1, etc. I could do:

void callback_mem_func1(...) {
// call user function passed in via connect_interrupt
cb_base &cb = *user_cb[0]; // <<<<NOTE HERE>>>
}
void callback_mem_func2(...) {
// call user function passed in via connect_interrupt
cb_base &cb = *user_cb[1]; // <<<<NOTE HERE>>>
}
or ... I'm open to a re-design worse case.

// cb_base:

# include <iostream>
# include <memory>
# include <string>

using namespace std;
class cb_base
{
public:
virtual void operator()(...) const {};
virtual ~cb_base() = 0;
};

inline cb_base::~cb_base() {}

template <typename T>
class cb_derived : public cb_base
{
public:
typedef void (T::*F)(...);
cb_derived( T& t, F f) : t_(&t), f_(f) {}
void operator()(...) const
{
(t_->*f_)();
}

private:
T* t_;
F f_;
};

template <typename T>
cb_derived<T> make_callback (T& t, void (T::*f)(...) )
{
return cb_derived<T>(t, f);
}

template <class T>
std::auto_ptr<cb_base> new_callback(T& t, void (T::*f)(...))
{
return std::auto_ptr<cb_base>(new cb_derived<T>(t, f));
}


Thanks in advance
 
M

Maxim Yegorushkin

Select parameters in a vendors API file is as follows:

#ifdef __cplusplus
typedef void (*VOIDFUNCPTR)(...); /* ptr to function returning void
*/
#else
typedef void (*VOIDFUNCPTR)(); /* ptr to function returning void
*/
#endif /* __cplusplus */

enum CAUSE { CHAN0_COMPLETE, CHAN0_MISS, CHAN0_HIT, CHAN0_ISM };
bool IntConnect( CAUSE c, VOIDFUNCPTR p, int idx, int jdx);
// end vendors file

Are you sure that VOIDFUNCPTR takes no arguments before the ellipsis?
Because as it's declared now there is no way to get arguments from
inside VOIDFUNCPTR callback.
 
M

ma740988

I'm sure. That is the way VOIDFUNCPTR is declared. It was a surprise
to me when I encountered it. I never understood the need for the
ellipsis.
 
M

Maxim Yegorushkin

I'm sure. That is the way VOIDFUNCPTR is declared. It was a surprise
to me when I encountered it. I never understood the need for the
ellipsis.

Then it seems to be no way to pass any data to the callback, the
callback has to operate on global data.
 
M

ma740988

Yeah but the more important questions is what's teh workaround for
'user_cb'?. user_cb needs to reflect a list/vector or .......... How
would you achieve this?
 
M

Maxim Yegorushkin

Yeah but the more important questions is what's teh workaround for
'user_cb'?. user_cb needs to reflect a list/vector or .......... How
would you achieve this?

I'd do something along these lines:

typedef void (*VOIDFUNCPTR)();

enum CAUSE { CHAN0_COMPLETE, CHAN0_MISS, CHAN0_HIT, CHAN0_ISM };
bool IntConnect( CAUSE c, VOIDFUNCPTR p, int idx, int jdx);

template<int N> struct int_ {};

template<int N>
void the_callback(int_<N>); // implement it
// alternatively
// void the_callback(int_<CHAN0_COMPLETE>);
// void the_callback(int_<CHAN0_MISS>);

template<int N>
void callback_thunk()
{
the_callback(int_<N>());
}

void f()
{
IntConnect(CHAN0_COMPLETE, callback_thunk<CHAN0_COMPLETE>, 0, 0);
IntConnect(CHAN0_MISS, callback_thunk<CHAN0_MISS>, 0, 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

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top