std::auto_ptr / template question

M

ma740988

Part of my confusion here is certainly my ignorance of templates and
std::auto_ptr. Two topics, I've perused but need to really _delve_
into. In any event, consider the 'test' source.

# include <iostream>
# include <memory>
class CallbackBase
{
public:
virtual void operator()() const { };
virtual ~CallbackBase() = 0;
};

CallbackBase::~CallbackBase() { }

template<typename T>
class Callback : public CallbackBase
{
public:
typedef void (T::*F)();

Callback( T& t, F f ) : t_(&t), f_(f) { }
void operator()() const { (t_->*f_)(); }

private:
T* t_;
F f_;
};

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

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

class XYZ {
std::auto_ptr<CallbackBase> my_cb;
static void cb_test()
{
// call the user function passed in to the
// constructor of the sndr & slComm.
//CallbackBase& cb = *static_cast<CallbackBase*>(&my_cb.get());
//cb();
}
public:
template<typename T>
XYZ( T& t,
void(T::*f)() )
: my_cb( new_callback(t,f) )
{}
};

class use {
XYZ *x;
public:
use()
{
x = new XYZ(this, use::test_funct); // DOESN'T WORK
}
void test_funct() {
std::cout << " test_func called " << std::endl;
}
~use () { delete x; }
};

int main()
{
//use u;
}

1 ////
I'm trying to create an instance of the class XYZ within 'use'
constructor but the .NET 2003 compiler complains, that the constructor
for XYZ does _not_ take 2 parameters.

'XYZ::XYZ' : function does not take 2 parameters

Make no sense.

2////
Within the cb_test member function whats the right approach to calling
the void function passed into XYZ?
The commented out portion. i.e.

//CallbackBase& cb = *static_cast<CallbackBase*>(&my_cb.get());
//cb();
doesn't work
 
J

Jonathan Mcdougall

Part of my confusion here is certainly my ignorance of templates and
std::auto_ptr. Two topics, I've perused but need to really _delve_

It seems to be more with the basics than with std::auto_ptr and
templates.
into. In any event, consider the 'test' source.
# include <iostream>
# include <memory>

class CallbackBase
{
public:
virtual void operator()() const { };
virtual ~CallbackBase() = 0;

};

CallbackBase::~CallbackBase() { }

template<typename T>
class Callback : public CallbackBase
{
public:
typedef void (T::*F)();

Callback( T& t, F f ) : t_(&t), f_(f) { }
void operator()() const { (t_->*f_)(); }

private:
T* t_;
F f_;

};

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

}

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

class XYZ {
std::auto_ptr<CallbackBase> my_cb;
static void cb_test()
{
// call the user function passed in to the
// constructor of the sndr & slComm.
//CallbackBase& cb = *static_cast<CallbackBase*>(&my_cb.get());
//cb();
}
public:
template<typename T>
XYZ( T& t,
void(T::*f)() )
: my_cb( new_callback(t,f) )
{}

};

class use {
XYZ *x;
public:
use()
{
x = new XYZ(this, use::test_funct); // DOESN'T WORK

Of course. this is a pointer, not a reference, and member functions do
not decay to their address like free functions do.

x = new XYZ(*this, &use::test_funct);
}
void test_funct() {
std::cout << " test_func called " << std::endl;
}
~use () { delete x; }

};

int main()
{
//use u;

}

1 ////
I'm trying to create an instance of the class XYZ within 'use'
constructor but the .NET 2003 compiler complains, that the constructor
for XYZ does _not_ take 2 parameters.

'XYZ::XYZ' : function does not take 2 parameters

If that's the actual message, it is poorly diagnosed. It should be
something like "no instance of constructor XYZ::XYZ matches the
argument list".
Make no sense.

You must learn (unfortunately) to interpret compiler errors.
2////
Within the cb_test member function whats the right approach to calling
the void function passed into XYZ?
The commented out portion. i.e.

//CallbackBase& cb = *static_cast<CallbackBase*>(&my_cb.get());
//cb();
doesn't work

Well cb_test() is static and 'my_cb' is not, so that's illegal. Either
make cb_test() non static of 'my_cb' static and it should work with

CallbackBase &cb = *my_cb;
cb();

or simply

(*my_cb)();

By the way, what do you gain by allocation callbacks on the heap?


Jonathan
 
M

Maxim Yegorushkin

[]
class XYZ {
std::auto_ptr<CallbackBase> my_cb;
static void cb_test()
{
// call the user function passed in to the
// constructor of the sndr & slComm.
//CallbackBase& cb = *static_cast<CallbackBase*>(&my_cb.get());
//cb();

You can invoke it simply:

(*my_cb)();
}
public:
template<typename T>
XYZ( T& t,
void(T::*f)() )
: my_cb( new_callback(t,f) )
{}
};

class use {
XYZ *x;
public:
use()
{
x = new XYZ(this, use::test_funct); // DOESN'T WORK

You must use an ampersand for taking a member function address and pass a
reference to *this, rather than this.

x = new XYZ(*this, &use::test_funct);
 
I

Ivan Vecerina

Part of my confusion here is certainly my ignorance of templates and
std::auto_ptr. Two topics, I've perused but need to really _delve_
into. In any event, consider the 'test' source.

Actually, neither of the 2 errors you have reported is caused
by auto_ptr or templates -- although their presence makes it
difficult to find the problem (as your compiler may not
give very helpful error messages).
[not that it wouldn't be a good idea to study those 2 features]
# include <iostream>
# include <memory>
class CallbackBase
{
public:
virtual void operator()() const { };
virtual ~CallbackBase() = 0;
};

CallbackBase::~CallbackBase() { }

template<typename T>
class Callback : public CallbackBase
{
public:
typedef void (T::*F)();

Callback( T& t, F f ) : t_(&t), f_(f) { }
void operator()() const { (t_->*f_)(); }

private:
T* t_;
F f_;
};

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

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

class XYZ {
std::auto_ptr<CallbackBase> my_cb;
static void cb_test()
{
// call the user function passed in to the
// constructor of the sndr & slComm.
//CallbackBase& cb = *static_cast<CallbackBase*>(&my_cb.get());
//cb();

The proper syntax would be:
(*my_cb)(); // or (*my_cb.get())()
Which of course can be written in two steps:
CallbackBase& cb = *my_cb; // no cast required...
cb();

HOWEVER:
cb_test() being a *static* member function, it can only
access global variables or other static members of the class.
It cannot access a non-static member of cb_test().

So for the code to compile, my_cb() would have to be
a static data member of XYZ:
static std::auto_ptr<CallbackBase> my_cb;

You have to keep in mind that if you create multiple
instances of class XYZ, all these instances will share
the same "copy" of my_cb.
}
public:
template<typename T>
XYZ( T& t,
void(T::*f)() )
: my_cb( new_callback(t,f) )
{}
};

class use {
XYZ *x;
public:
use()
{
x = new XYZ(this, use::test_funct); // DOESN'T WORK

The first parameter needs to be an object reference ('this'
is a pointer), and you need a & to take the address of a
member function.
The corrected line becomes:
x = new XYZ(*this, &use::test_funct);
}
void test_funct() {
std::cout << " test_func called " << std::endl;
}
~use () { delete x; }
};


I hope this helps,
Ivan
 
I

Ivan Vecerina

Jonathan Mcdougall said:
....
By the way, what do you gain by allocation callbacks on the heap?

Subclasses of CallbackBase have to be allocated on the heap
to be used polymorphically at run-time: by calling the base
class, 'users' may call any type of object (via a Callback<T>
subclass).
So this is a correct approach.

This said: one could use a pointer to a (template-implemented)
function as an adaptor, rather than a class hierarchy.


Ivan
 
M

ma740988

| It seems to be more with the basics than with std::auto_ptr and
templates.
True and admittidely, I purchased a slew of highly recommended books
from accu but when it comes to templates and auto_ptr, I just 'scanned'
them with the intent to revisit later.

|x = new XYZ(*this, &use::test_funct);
Still doesn't work. Same error:
c:\sw_dev\C++\test\test.cpp(72) : error C2660: 'XYZ::XYZ' : function
does not take 2 parameters

Here's my confusion though: Can you have a template constructor in a
non-template class?

| By the way, what do you gain by allocation callbacks on the heap?
Sounds like the member function 'make_callback' is the right approach
as opposed to 'new_callback'
 
M

ma740988

| Still doesn't work. Same error:

Oops!! Never mind. The error generated by the compiler is so
CRYPTIC. Anyways, the 'static' keyword on the member function
test_func was doing injustice.

Thanks ALL !!!!!
 
J

Jonathan Mcdougall

class CallbackBase
Subclasses of CallbackBase have to be allocated on the heap
to be used polymorphically at run-time: by calling the base
class, 'users' may call any type of object (via a Callback<T>
subclass).
So this is a correct approach.

Well I certainly missed the virtual functions in CallbackBase, but I
don't see how, with the current design, they are useful. If the OP
projects to have other types of callbacks (such as for free functions),
I stand corrected.

Jonathan
 
I

Ivan Vecerina

Jonathan Mcdougall said:
Well I certainly missed the virtual functions in CallbackBase, but I
don't see how, with the current design, they are useful. If the OP
projects to have other types of callbacks (such as for free functions),
I stand corrected.

If not, the problem is not only the pointless heap allocation,
but also the irrelevant Callback class hierarchy.

We agree -Ivan
 
M

ma740988

| So for the code to compile, my_cb() would have to be a static data
member of XYZ:
| static std::auto_ptr<CallbackBase> my_cb;

Got it. So the templated constructor for XYZ becomes

template<typename T>
XYZ( T& t, void(T::*f)() )
// : my_cb( new_callback(t,f) ) // can't use initilization list on
static 'items'
{
my_cb = new_callback(t,f);
}

Make sense!! You guys are good. Thanks
 
M

ma740988

| If the OP projects to have other types of callbacks (such as for free
functions),

Jonathan, that's correct. Thanks again
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top