C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

problem with template recursion

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Marco Jez
Guest





PostPosted: Mon Sep 19, 2005 5:15 pm    Post subject: problem with template recursion Reply with quote



I've already posted this question to clc++ but it wasn't helpful, so I'm
trying here.
I'm rewriting an introspection library I wrote some time ago, introducing
new features and improving consistency between the run-time rules provided
by the library (name lookup, type conversions, cv qualifiers, etc.) and
those provided at compile time by the C++ language.
In the library core lies a class named "object" whose purpose is to act as a
container for objects of any type. It works pretty much like boost::any,
although it differs slightly in the semantics (but that's not relevant to my
question). This is an example of how this class is supposed to be used:

// x contains a const char*
object x = "hello, world";

int n = 10;

// y contains an int
object y = n;

// z contains an int*
object z = &n;


Pretty straightforward, no problems up to here. Class "object" is roughly
defined as follows (many details omitted for clarity):

class object
{
public:
template<typename T>
object(const T &v): _inst(new instance<T>(v)) {}

protected:
struct instance_base
{
virtual ~instance_base() {}
};

template<typename T>
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
};

private:
instance_base* _inst;
};

Now I want to give the user the ability to create new objects (that is, new
instances of class "object") by either creating pointers to or dereferencing
existing ones. An example should clarify what I mean:

// x holds an int
object x = 10;

// ideally, y should hold a pointer to the value held by x.
// the private member y::_inst should be of type object::instance<int*>
object y = make_pointer(x);

// ideally, z should hold the same value as x
object z = dereference(y);


My first attempt to implement this behaviour was to add a virtual method to
object::instance_base:

struct instance_base
{
...
virtual instance_base* mkptr() = 0;
...
};

and its concrete implementation in object::instance<T>:

template<typename T>
struct instance: instance_base
{
...
instance_base* mkptr() { return new instance<T*>(&_val); }
...
};


The idea was to let an external function like make_pointer() access the
object::_inst member and call its mkptr() method in order to create the new
object. Unfortunately this doesn't compile because it generates an infinite
recursion.

So, here's finally the question: how can I implement this behaviour so that
actions like those of the example above are possible?

Cheers,
Marco



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Przemyslaw Szymanski
Guest





PostPosted: Tue Sep 20, 2005 11:19 am    Post subject: Re: problem with template recursion Reply with quote



Marco Jez wrote:
[...]
Quote:
template<typename T
struct instance: instance_base
{
...
instance_base* mkptr() { return new instance ...
};


The idea was to let an external function like make_pointer() access the
object::_inst member and call its mkptr() method in order to create the new
object. Unfortunately this doesn't compile because it generates an infinite
recursion.

So, here's finally the question: how can I implement this behaviour so that
actions like those of the example above are possible?


Hello,

You need to define a partial specialization of object::instance for T*:

template <typename T>
struct instance<T*> : public instance_base
{
instance(const T* val): _val(val) {}
instance_base* mkptr() { return new instance<T*>(_val); }
//the following would cause infinite recursion too
//instance_base* mkptr() { return new instance<T**> (&_val); }
T* _val;
};

Przemek.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
ylegoc
Guest





PostPosted: Tue Sep 20, 2005 11:21 am    Post subject: Re: problem with template recursion Reply with quote




Marco Jez a écrit :

Quote:
I've already posted this question to clc++ but it wasn't helpful, so I'm
trying here.
I'm rewriting an introspection library I wrote some time ago, introducing
new features and improving consistency between the run-time rules provided
by the library (name lookup, type conversions, cv qualifiers, etc.) and
those provided at compile time by the C++ language.
In the library core lies a class named "object" whose purpose is to act as a
container for objects of any type. It works pretty much like boost::any,
although it differs slightly in the semantics (but that's not relevant to my
question). This is an example of how this class is supposed to be used:

// x contains a const char*
object x = "hello, world";

int n = 10;

// y contains an int
object y = n;

// z contains an int*
object z = &n;


Pretty straightforward, no problems up to here. Class "object" is roughly
defined as follows (many details omitted for clarity):

class object
{
public:
template<typename T
object(const T &v): _inst(new instance
protected:
struct instance_base
{
virtual ~instance_base() {}
};

template<typename T
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
};

private:
instance_base* _inst;
};

Now I want to give the user the ability to create new objects (that is, new
instances of class "object") by either creating pointers to or dereferencing
existing ones. An example should clarify what I mean:

// x holds an int
object x = 10;

// ideally, y should hold a pointer to the value held by x.
// the private member y::_inst should be of type object::instance object y = make_pointer(x);

// ideally, z should hold the same value as x
object z = dereference(y);


My first attempt to implement this behaviour was to add a virtual method to
object::instance_base:

struct instance_base
{
...
virtual instance_base* mkptr() = 0;
...
};

and its concrete implementation in object::instance
template<typename T
struct instance: instance_base
{
...
instance_base* mkptr() { return new instance ...
};


The idea was to let an external function like make_pointer() access the
object::_inst member and call its mkptr() method in order to create the new
object. Unfortunately this doesn't compile because it generates an infinite
recursion.

So, here's finally the question: how can I implement this behaviour so that
actions like those of the example above are possible?

Cheers,
Marco

Here is my solution:

The problem is that we cannot call the object constructor in the
following line:

object y = make_pointer(x);

since x is an object of which type is known at compile-time. That is
why make_pointer must return an object.

Thus we have to define a copy constructor in the object class as well
as a constructor that takes an instance_base pointer in parameter.
Indeed the instantiation of the instance_base must be done in the
derived class.

Furthermore, personnaly I would prefer overload the & and * operator to
provide a more intuitive syntax.

implementation:

class object
{
public:
template<typename T>
object(const T &v): _inst(new instance<T>(v)) {}

// copy constructor
object(const object & obj): _inst(obj._inst->clone()) {}

// address-of operator
object operator& () const
{
// call to constructor from instance_base *
return object(_inst->make_pointer());
}

// dereference operator
object operator* () const
{
...
}

// don't forget destructor
~object()
{
delete _inst;
}
protected:
struct instance_base
{
virtual ~instance_base() {}

// added method
virtual instance_base * clone() const;
virtual instance_base * make_pointer() const;
};

template<typename T>
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;

virtual instance_base * clone() const {...}
virtual instance_base * make_pointer() const {...}
};

private:
// constructor from instance_base *
object(instance_base * inst) : _inst(inst) {}

instance_base* _inst;
};

You can use it as follows:

object x(10);
object y(&x);
object z(*y);

The code is not complete, but I hope this helps you.

Yannick Le Goc

Software engineer at ObjetDirect
France


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Marco Jez
Guest





PostPosted: Tue Sep 20, 2005 1:56 pm    Post subject: Re: problem with template recursion Reply with quote

Quote:
since x is an object of which type is known at compile-time. That is
why make_pointer must return an object.

Thus we have to define a copy constructor in the object class as well
as a constructor that takes an instance_base pointer in parameter.
Indeed the instantiation of the instance_base must be done in the
derived class.

Furthermore, personnaly I would prefer overload the & and * operator to
provide a more intuitive syntax.

Thanks but this doesn't solve my problem: what to put in
instance<>::make_pointer() ?
Whether I use overloaded operators or other methods to call
instance::make_pointer(), and whether I set the _inst member from an
external friend function or in an initialization constructor, it really
doesn't make any difference. instance<T>::make_pointer() will always need to
create an instance<T*> in order to create the actual pointer, and this
causes a compile-time recursion that I can't get rid of :-/

Cheers,
Marco


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Marco Jez
Guest





PostPosted: Tue Sep 20, 2005 1:56 pm    Post subject: Re: problem with template recursion Reply with quote

Quote:
template <typename T
struct instance {
instance(const T* val): _val(val) {}
instance_base* mkptr() { return new instance<T*>(_val); }
//the following would cause infinite recursion too
//instance_base* mkptr() { return new instance<T**> (&_val); }
T* _val;
};

This wouldn't allow recursive pointers, that is:

object x = make_pointer(make_pointer(make_pointer(y)));

Unfortunately I can't limit the usage of make_pointer() to a single level of
indirection.

Marco


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Zhen Yao
Guest





PostPosted: Wed Sep 21, 2005 9:05 am    Post subject: Re: problem with template recursion Reply with quote

Then what about restricting the level of indirections to a certain
limit?

template <typename T>
struct instance<T****************************> : instance_base
{
typedef T**************************** value_type;
instance(const value_type& val) : _val(val) {}

instance_base* mkptr()
{
assert(0);
return 0;
}

value_type _val;
};

By using some preprocessor magic, the maximum level of indirections can
also be defined using a preprocessor macro.
Is this workaround acceptable for you?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Greg Herlihy
Guest





PostPosted: Wed Sep 21, 2005 9:07 am    Post subject: Re: problem with template recursion Reply with quote

Marco Jez wrote:
Quote:
since x is an object of which type is known at compile-time. That is
why make_pointer must return an object.

Thus we have to define a copy constructor in the object class as well
as a constructor that takes an instance_base pointer in parameter.
Indeed the instantiation of the instance_base must be done in the
derived class.

Furthermore, personnaly I would prefer overload the & and * operator to
provide a more intuitive syntax.

Thanks but this doesn't solve my problem: what to put in
instance<>::make_pointer() ?
Whether I use overloaded operators or other methods to call
instance::make_pointer(), and whether I set the _inst member from an
external friend function or in an initialization constructor, it really
doesn't make any difference. instance<T>::make_pointer() will always need to
create an instance<T*> in order to create the actual pointer, and this
causes a compile-time recursion that I can't get rid of :-/

Cheers,
Marco

The infinite recursion stems from the fact that object<T>::make_ptr
instantiates and returns an object<T*> whose own make_ptr method
instantiates and returns an object<T**> which in turn - well I don't
have the patience to type the entire sequence out. But suffice it to
say this pattern goes on for a while, if not longer.

The simplest solution would be to declare make_ptr a standalone
function template. To do so, I would first make object the template
class. As currently implemented, the type used to construct an object
object [sic] is not retained. A holder of such an object has no way of
determining the type it holds. Such a loss of type information
nullifies one of the primary benefits of using templates. To put it
another way, without the type information, object may as well be
holding void *.

So let's assume object is a class template implemented along these
lines for type T:

template <typename T>
struct object
{
object( T& t) : t_(t) {}

T* get_ptr() const
{
return &t_;
}

private:
T& t_;
};

We will also need a specialization of object when T is a pointer type
(which would include pointer-to-pointer types):

template <typename T>
struct object<T*>
{
object( T* t) : t_(t) {}

T** get_ptr() { return &t_; }

private:
T* t_;
};

Finally, we just need a standalone make_ptr routine to return an
object<T*> for an object<T>:

template <typename T>
object<T*>
make_ptr( object<T>& inObject)
{
return object<T*>( inObject. get_ptr() ):
}

As a standalone function template make_ptr is instantiated only from
calls to it that appear in the source code - of which there can be only
a finite number Furthermore since make_ptr does not call itself either
diretly or indirectly, there is no infinite recursion.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Marco Jez
Guest





PostPosted: Wed Sep 21, 2005 11:53 am    Post subject: Re: problem with template recursion Reply with quote

"Zhen Yao" <allen.yao (AT) gmail (DOT) com> ha scritto nel messaggio
news:1127269404.428095.54100 (AT) g14g2000cwa (DOT) googlegroups.com...
Quote:
Then what about restricting the level of indirections to a certain
limit?

This will certainly be my final solution unless I find a better one soon. I
was just hoping there was a clean way to do that without imposing any
restrictions... :-/

Thanks,
Marco


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Marco Jez
Guest





PostPosted: Wed Sep 21, 2005 11:54 am    Post subject: Re: problem with template recursion Reply with quote

Quote:
The simplest solution would be to declare make_ptr a standalone
function template. To do so, I would first make object the template
class. As currently implemented, the type used to construct an object
object [sic] is not retained. A holder of such an object has no way of
determining the type it holds. Such a loss of type information
nullifies one of the primary benefits of using templates. To put it
another way, without the type information, object may as well be
holding void *.

Actually, making object a template would nullify the purpose of class object
itself: hiding the underlying instance's type at compile time, while making
it accessible at run time (as boost::any does). As I stated in my first
post, I'm writing an introspection/reflection library, so everything
revolves around this compile-time to run-time promotion. Please note that an
introspection library does NOT aim to bypass C++'s strong-typed nature for
doing the same tasks that could be done much more efficiently at compile
time through templates, instead it aims to:
- provide better run-time type information than standard RTTI;
- provide the means for accessing objects, calling functions, etc. without
needing compile-time knowledge of data types and function signatures by
providing the necessary abstractions (like the class being described here).
This feature is meant to be used mainly for interfacing C++ programs with
scripting languages, serializing objects and, more generally, for providing
out-of-the-box run-time access to any C++ object and function under the same
abstract interface.

Cheers,
Marco


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Graeme Prentice
Guest





PostPosted: Thu Sep 22, 2005 2:38 pm    Post subject: Re: problem with template recursion Reply with quote

On 19 Sep 2005 13:15:30 -0400, Marco Jez wrote:

[snip]

Quote:
// x holds an int
object x = 10;

// ideally, y should hold a pointer to the value held by x.
// the private member y::_inst should be of type object::instance<int*

but the type of y::_inst is always pointer to instance_base, so I guess
you mean the type of the object y::_inst points at


Quote:
object y = make_pointer(x);

// ideally, z should hold the same value as x
object z = dereference(y);




One possibility that *might* work is to store an extra pointer in the
object object (sic again!) - this is a pointer to a function that knows
how to create instance you also have to change _mf.

I attempted to move this extra pointer into the heap object but didn't
solve the recursion problem so far.


class object
{
public:
template<typename T>
object(const T &v): _inst(new instance<T>(v)),
_mf(&mkptr<T>) {}

protected:
struct instance_base
{
virtual ~instance_base() {}
virtual void* get_address() = 0;
};

template<typename T>
static instance_base * mkptr(instance_base * bp)
{
return new instance<T*>((T*)bp->get_address());
}

template<typename T>
struct instance: instance_base
{
instance(const T &val): _val(val) {}
T _val;
void* get_address() { return &_val; }
//instance_base* mkptr() {} return new instance<T*>(&_val); }

};

private:
instance_base* _inst;
typedef instance_base * (*mf)(instance_base *);
mf _mf;
};

int main()
{
object x = 10;
}

Graeme

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Graeme Prentice
Guest





PostPosted: Fri Sep 23, 2005 2:28 pm    Post subject: Re: problem with template recursion Reply with quote

On 22 Sep 2005 10:38:57 -0400, Graeme Prentice wrote:

Quote:



One possibility that *might* work is to store an extra pointer in the
object object (sic again!) - this is a pointer to a function that knows
how to create instance<T*> objects. If you change the value of _inst,
you also have to change _mf.


Well, except that not long after posting this I realised that this
doesn't solve the recursion problem at all, which can probably only be
solved by setting a recursion max depth with specializations.

Graeme

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.